2020 ICPC Asia East Continent Final D. City Brain(最短路+三分)
阿新 • • 發佈:2021-08-20
題意:
給出\(n\) 個點,\(m\)條邊的無向帶權圖,初始邊權都為\(1\),一共有\(k\) 次操作機會,每次操作可以選擇一條邊使其邊權\(+1\), 通過一條邊的時間為 \(1/\)邊權 ,求\(min(dis(s1,t1)+dis(s2,t2))\)
題解:
考慮列舉兩條路徑的公共起點和終點,假設長度 \(x\) , 對於剩下的各自走的邊長度為 \(y\) ,貪心的考慮,肯定是將操作次數均分最好,即對於長度為\(l\) ,操作次數為 \(t\) ,最優時間肯定是 \((t\%l)/(2+t/l)+(l-t\%l)/(1+t/l)\)
然後考慮三分公共路徑上分到的操作次數 ,時間複雜度為\(O(n^2logn)\)
再貪心的想,對於公共長度固定,那肯定是讓各自長度越小越好,所有可以先\(n^2\) 跑最短路,然後預處理出每個公共長度的最小各自長度 ,最後再三分即可。
程式碼:
#pragma GCC diagnostic error "-std=c++11" #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #include<map> #include<stack> #include<set> #include<ctime> #define iss ios::sync_with_stdio(false) using namespace std; typedef unsigned long long ull; typedef long long ll; typedef pair<int,int> pii; const int mod=1e9+7; const int MAXN=5e3+5; const int inf=0x3f3f3f3f; int dis[MAXN][MAXN],vis[MAXN]; vector<int> g[MAXN]; int dp[MAXN]; int n, m, k; void bfs(int u) { dis[u][u] = 0; queue<pii> q; q.push({ u, 0 }); vis[u] = 1; while(!q.empty()) { pii now = q.front(); q.pop(); for(auto v:g[now.first]) { if(vis[v]) continue; dis[u][v] = dis[u][now.first] + 1; vis[v] = 1; q.push({ v, dis[u][v] }); } } } bool ok(int s,int i,int j,int t) { if(dis[s][i]!=inf&&dis[i][j]!=inf&&dis[j][t]!=inf) return true; else return false; } double get_cost(int x,int y) { int c1 = 1 + y / x; int c2 = 2 + y / x; double ans1 = 1.0 * (x - y % x) / c1; double ans2 = 1.0 * (y % x) / c2; return ans1 + ans2; } double cal(int x,int y) { if(!x&&!y) return 0; else if(!x) return 2*get_cost(y,k); else if(!y) return get_cost(x,k); else { double ans = 1e9; int l = 0, r = k; while(l<=r) { int mid1 = l + (r - l) / 3; int mid2 = r - (r - l) / 3; double v1 = 2 * get_cost(y, mid1) + get_cost(x, k - mid1); double v2 = 2 * get_cost(y, mid2) + get_cost(x, k - mid2); if(v1<v2) { ans = v1; r = mid2-1; } else { ans = v2; l = mid1+1; } } return ans; } } int main() { memset(dis, inf, sizeof dis); memset(dp, inf, sizeof dp); scanf("%d%d%d", &n, &m, &k); for (int i = 1; i <= m;i++) { int u, v; scanf("%d%d", &u, &v); g[u].push_back(v); g[v].push_back(u); } int s1, t1, s2, t2; scanf("%d%d%d%d", &s1, &t1, &s2, &t2); for (int i = 1; i <= n;i++) { for (int j = 1; j <= n;j++) vis[j] = 0; bfs(i); } //cout << 1 << endl; dp[0] = dis[s1][t1] + dis[s2][t2]; for (int i = 1; i <= n;i++) { for (int j = 1; j <= n;j++) { if ((ok(s1, i, j, t1) || ok(s1, j, i, t1)) && (ok(s2, i, j, t2) || ok(s2, j, i, t2))) { int d = dis[i][j]; dp[d] = min(dp[d], min(dis[s1][i] + dis[j][t1], dis[s1][j] + dis[i][t1]) + min(dis[s2][i] + dis[j][t2], dis[s2][j] + dis[i][t2])); } } } double ans = 1e9; //cout << 1 << endl; for (int i = 0; i <= n;i++) { if(dp[i]==inf) continue; ans = min(ans, cal(dp[i], i)); } printf("%.15lf\n", ans); }