SRM590Hard
题意
给 \(n\) 个点的连通无向图和 \(a_0,\ a_1,\ ...,\ a_{n\ -\ 1}\)。
问添加一些(可以不加)边后 \(\sum_{i\ =\ 0}^{n\ -\ 1}\ (dist_{0,\ i}\ -\ a_i)^2\) 最小是多少。
\(1\ \leq\ n\ \leq\ 40\)
做法1
考虑网络流。
合法的 \(dist_{0,\ i}\) 数组应满足:
1.\(dist_{0,\ 0}\ =\ 0\)
2.\(dist_{0,\ i}\ >\ 0,\ (1\ \leq\ i)\)
3.\(\forall\ (u,\ v)\ \in\ E,\ |dist_{0,\ u}\ -\ dist_{0,\ v}|\ \leq\ 1\),其中 \(E\) 是输入的边集。
于是可以将一个点 \(u\) 拆成 \((u,\ 0),\ (u,\ 1),\ ...,\ (u,\ n\ -\ 1)\),相邻两个连一条流量为代价的边,并连 \(S,\ (u,\ 0)\) 流量为 \(\infty\) 和 \((u,\ n\ -\ 1),\ T\) 流量为代价。
处理 \(3.\) 的限制时将 \((u,\ i)\) 向 \((v,\ i\ -\ 1)\) 连边, \((v,\ i)\) 向 \((u,\ i\ -\ 1)\) 连流量为 \(\infty\) 的边即可。最小割即为所求。
代码
#line 2 "FoxAndCity.cpp"
#include <bits/stdc++.h>
#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif
#ifdef __WIN32
#define LLFORMAT "I64"
#define Rand() ((rand() << 15) + rand())
#else
#define LLFORMAT "ll"
#define Rand() (rand())
#endif
using namespace std;
class FoxAndCity {
public:
int minimalCost(vector <string> linked, vector <int> want) ;
// BEGIN CUT HERE
public:
void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); if ((Case == -1) || (Case == 5)) test_case_5(); if ((Case == -1) || (Case == 6)) test_case_6(); }
private:
template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
void test_case_0() { string Arr0[] = {"NYN",
"YNY",
"NYN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0, 1, 1}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 0; verify_case(0, Arg2, minimalCost(Arg0, Arg1)); }
void test_case_1() { string Arr0[] = {"NYNN",
"YNYN",
"NYNY",
"NNYN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0, 3, 3, 3}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 5; verify_case(1, Arg2, minimalCost(Arg0, Arg1)); }
void test_case_2() { string Arr0[] = {"NYNNNY",
"YNYNNN",
"NYNYNN",
"NNYNYN",
"NNNYNY",
"YNNNYN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0, 2, 2, 2, 2, 2}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 2; verify_case(2, Arg2, minimalCost(Arg0, Arg1)); }
void test_case_3() { string Arr0[] = {"NYY","YNN","YNN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0,0,0}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 2; verify_case(3, Arg2, minimalCost(Arg0, Arg1)); }
void test_case_4() { string Arr0[] = {"NYNNNN",
"YNYNNN",
"NYNYYY",
"NNYNYY",
"NNYYNY",
"NNYYYN"}
; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0, 1, 2, 3, 0, 3}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 3; verify_case(4, Arg2, minimalCost(Arg0, Arg1)); }
void test_case_5() { string Arr0[] = {"NYNNNN",
"YNYNNN",
"NYNYYY",
"NNYNYY",
"NNYYNY",
"NNYYYN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0, 1, 2, 4, 0, 4}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 6; verify_case(5, Arg2, minimalCost(Arg0, Arg1)); }
void test_case_6() { string Arr0[] = {"NYNYYYYYYYY","YNYNNYYNYYY","NYNNNYYNYYN","YNNNYYYYYYY","YNNYNYYYNYY","YYYYYNNYYNY","YYYYYNNNYYY","YNNYYYNNNYY","YYYYNYYNNNY","YYYYYNYYNNY","YYNYYYYYYYN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0,1,2,0,0,5,1,3,0,2,3}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 28; verify_case(6, Arg2, minimalCost(Arg0, Arg1)); }
// END CUT HERE
} ___test;
// BEGIN CUT HERE
int main() {
int test_case;
scanf("%d", &test_case);
___test.run_test(test_case);
}
// END CUT HERE
//----------head----------
const int maxv = 1710, maxe = 1e6 + 10, oo = 1e9;
int n, to[maxe], nxt[maxe], cap[maxe], head[maxv], S, T, m, d[maxv], iter[maxv];
void add_edge(int u, int v, int c) { to[m] = v; nxt[m] = head[u]; cap[m] = c; head[u] = m++; return; }
void add_biedge(int u, int v, int c) { add_edge(u, v, c); add_edge(v, u, 0); return; }
bool bfs() {
static int q[maxv], fnt, rar;
fnt = rar = 0; q[rar++] = S;
memset(d, -1, sizeof(d[0]) * n); d[S] = 0;
while(fnt != rar) {
int u = q[fnt++];
for (int i = head[u]; ~i; i = nxt[i]) if(cap[i] && !~d[to[i]]) d[q[rar++] = to[i]] = d[u] + 1;
}
return ~d[T];
}
int dfs(int u = S, int f = oo) {
if(u == T) return f;
int t = f;
for (int v, &i = iter[u]; ~i; i = nxt[i]) if(cap[i] && d[v = to[i]] == d[u] + 1) {
int F = dfs(v, min(t, cap[i]));
t -= F;
cap[i] -= F;
cap[i ^ 1] += F;
if(!t) return f;
}
return f - t;
}
int FoxAndCity::minimalCost(vector <string> linked, vector <int> want) {
int N = linked.size();
m = 0;
S = N * N; T = S + 1; n = T + 1;
memset(head, -1, sizeof(head[0]) * n);
for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) if(linked[i][j] == 'Y') {
for (int k = 1; k < N; ++k) add_biedge(i * N + k, j * N + k - 1, oo);
}
for (int i = 0; i < N; ++i) {
add_biedge(S, i * N, oo);
if(i == 0) {
for (int k = 1; k < N; ++k) add_biedge(i * N + k - 1, i * N + k, (k == 1 ? 0 : oo));
add_biedge(i * N + N - 1, T, oo);
}
else {
for (int k = 1; k < N; ++k) add_biedge(i * N + k - 1, i * N + k, (k == 1 ? oo : (want[i] - k + 1) * (want[i] - k + 1)));
add_biedge(i * N + N - 1, T, (want[i] - N + 1) * (want[i] - N + 1));
}
}
int ans = 0;
while(bfs()) {
memcpy(iter, head, sizeof(iter[0]) * n);
for (int f = dfs(); f; f = dfs()) ans += f;
}
return ans;
}