Topcoder SRM590 Fox And City
Problem Statement |
|
There is a country with n cities, numbered 0 through n-1. City 0 is the capital. The road network in the country forms an undirected connected graph. In other words: Some pairs of cities are connected by bidirectional roads. For every city there is at least one sequence of consecutive roads that leads from the city to the capital. (Whenever two roads need to cross outside of a city, the crossing is done using a bridge, so there are no intersections outside of the cities.) You are given a String[] linked that describes the road network. For each i and j, linked[i][j] is 'Y' if the cities i and j are already connected by a direct road, and it is 'N' otherwise. The distance between two cities is the smallest number of roads one needs to travel to get from one city to the other. The people living outside of the capital are usually unhappy about their distance from the capital. You are also given a int[] want with n elements. For each i, want[i] is the desired distance between city i and the capital (city 0). Fox Ciel is in charge of building new roads. Each new road must again be bidirectional and connect two cities. Once the new roads are built, the citizens will evaluate how unhappy they are with the resulting road network: For each i: Let real[i] be the new distance between city i and the capital. Then the people in city i increase the unhappiness of the country by (want[i] - real[i])^2. Return the minimal total unhappiness Ciel can achieve by building some (possibly zero) new roads. |
题目大意:给定n个点的无向图,边权均为1,每个点有一个属性wi,现在可以在图中任意加边,记加边后每个点到1号点的距离为di,最小化Σ(wi - di)^2.
样例:
Sample Input
3
NYN
YNY
NYN
0 1 1
4
NYNN
YNYN
NYNY
NNYN
0 3 3 3
6
NYNNNY
YNYNNN
NYNYNN
NNYNYN
NNNYNY
YNNNYN
0 2 2 2 2 2
3
NYY
YNN
YNN
0 0 0
6
NYNNNN
YNYNNN
NYNYYY
NNYNYY
NNYYNY
NNYYYN
0 1 2 3 0 3
6
NYNNNN
YNYNNN
NYNYYY
NNYNYY
NNYYNY
NNYYYN
0 1 2 4 0 4
11
NYNYYYYYYYY
YNYNNYYNYYY
NYNNNYYNYYN
YNNNYYYYYYY
YNNYNYYYNYY
YYYYYNNYYNY
YYYYYNNNYYY
YNNYYYNNNYY
YYYYNYYNNNY
YYYYYNYYNNY
YYNYYYYYYYN
0 1 2 0 0 5 1 3 0 2 3
Sample Output
0
5
2
3
6
28
分析:综合了许多知识的好题.
题目说可以任意加边,那么是不是就意味着每个点的最短路都是任意的呢? 显然不是的,考虑确定每个点的最短路有什么限制.
首先,d1 = 0. 然后对于任意有边的一对点(i,j),|di - dj| ≤ 1. 现在要求满足上述限制的最值.
这其实就是个离散变量模型,和bzoj3144类似. 先拆点,S向i号点拆出的0号点连容量为inf的边,i号点拆出的n-1号点向T连容量为inf的边. i号点拆出的k号点向k+1号点连容量为(a[i] - k - 1) ^ 2的边.
对于有限制的点对(i,j),i拆出的第k个点向j拆出的第k-1个点连容量为inf的边,j连i也同样如此.
还没完.必须保证d1 = 0.那么1拆出的第k个点向第k+1个点的边就不能被割. 将其容量变成inf就好了. 但是这样会存在一个问题:ST总是连通的. 因为S到T总是可以经过1号点拆出的点,这条路径上的每条边的容量都是inf,割不掉.
怎么解决呢?去掉S与1号点拆出的第一个点的连边就好了.
不断调整,满足最小割的要求,同时使得答案合理,这是最小割模型建图的一般分析方法.
同时这道题融合了最短路问题的一些技巧,例如hdu5385,每个点到源点的最短路都和与它相连的点的最短路有关.
#include <cstdio> #include <queue> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 300010,inf = 0x7fffffff; int n,a[50],id[50][50],cnt,head[maxn],to[maxn],nextt[maxn],w[maxn],tot = 2; int d[maxn],S,T,ans; char s[110][110]; void add(int x,int y,int z) { w[tot] = z; to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; w[tot] = 0; to[tot] = x; nextt[tot] = head[y]; head[y] = tot++; } bool bfs() { memset(d,-1,sizeof(d)); d[S] = 0; queue <int> q; q.push(S); while (!q.empty()) { int u = q.front(); q.pop(); if (u == T) return true; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (w[i] && d[v] == -1) { d[v] = d[u] + 1; q.push(v); } } } return false; } int dfs(int u,int f) { if (u == T) return f; int res = 0; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (w[i] && d[v] == d[u] + 1) { int temp = dfs(v,min(f - res,w[i])); w[i] -= temp; w[i ^ 1] += temp; res += temp; if (res == f) return res; } } if (!res) d[u] = -1; return res; } void dinic() { while(bfs()) ans += dfs(S,inf); } int main() { scanf("%d",&n); for (int i = 1; i <= n; i++) scanf("%s",s[i] + 1); for (int k = 0; k <= n - 1; k++) for (int i = 1; i <= n; i++) id[i][k] = ++cnt; S = cnt + 1; T = S + 1; add(id[1][n - 1],T,inf); for (int i = 2; i <= n; i++) add(S,id[i][0],inf),add(id[i][n - 1],T,inf); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { if (s[i][j] == 'Y') { for (int k = 1; k <= n - 1; k++) add(id[i][k],id[j][k - 1],inf); } } for (int i = 1; i <= n; i++) { int x; scanf("%d",&x); for (int j = 0; j <= n - 2; j++) add(id[i][j],id[i][j + 1],(i == 1 ? inf : (x - j - 1) * (x - j - 1))); } dinic(); printf("%d\n",ans); return 0; }