Solution
类似于这个题。
F
表示
建出这些点后,原图中的边
(u,v)
就相当于限制
|du−dv|≤1
。
还有
d1=0
。
di≠0,i=2..n
。只要保证相应的边不能被割到就好了。
// BEGIN CUT HERE
// END CUT HERE
#line 5 "FoxAndCity.cpp"
#include <bits/stdc++.h>
using namespace std;
const int N = 50;
const int INF = 1 << 29;
struct edge {
int to, next, flow;
edge(int t = 0, int n = 0, int f = 0):to(t), next(n), flow(f) {}
};
edge G[N * N * N * 10];
int head[N * N], cur[N * N];
int dis[N * N], vis[N * N];
int id[N][N];
int c[N];
int Gcnt, n, clc, S, T, cnt;
queue<int> Q;
inline void AddEdge(int from, int to, int flow) {
G[++Gcnt] = edge(to, head[from], flow); head[from] = Gcnt;
G[++Gcnt] = edge(from, head[to], 0); head[to] = Gcnt;
}
inline void Init(void) {
Gcnt = 1; cnt = 0; memset(head, 0, sizeof head);
}
inline bool bfs(int S, int T) {
Q.push(S); dis[S] = 0; vis[S] = ++clc;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
for (int i = head[u]; i; i = G[i].next) {
edge &e = G[i];
if (e.flow && vis[e.to] != clc) {
dis[e.to] = dis[u] + 1;
vis[e.to] = clc; Q.push(e.to);
}
}
}
return vis[T] == clc;
}
inline int dfs(int u, int a) {
if (u == T || !a) return a;
int f, flow = 0;
for (int &i = cur[u]; i; i = G[i].next) {
edge &e = G[i];
if (e.flow && dis[e.to] == dis[u] + 1
&& (f = dfs(e.to, min(e.flow, a))) > 0) {
e.flow -= f; G[i ^ 1].flow += f;
flow += f; a -= f; if (!a) break;
}
}
return flow;
}
inline int MaxFlow(int S, int T) {
int flow = 0;
while (bfs(S, T)) {
for (int i = 0; i <= T; i++) cur[i] = head[i];
flow += dfs(S, INF);
}
return flow;
}
inline int sqr(int x) {
return x * x;
}
class FoxAndCity {
public:
int minimalCost(vector <string> linked, vector <int> want) {
n = want.size(); Init();
for (int i = 1; i <= n; i++) {
c[i] = want[i - 1];
for (int j = 0; j < n; j++)
id[i][j] = ++cnt;
}
S = ++cnt; T = ++cnt;
for (int i = 1; i <= n; i++) {
if (i == 1) AddEdge(id[i][0], T, INF);
else AddEdge(S, id[i][0], INF);
AddEdge(S, id[i][0], sqr(c[i]));
for (int j = 1; j < n; j++)
AddEdge(id[i][j - 1], id[i][j], sqr(j - c[i]));
AddEdge(id[i][n - 1], T, INF);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i != j && linked[i - 1][j - 1] == 'Y')
for (int k = 1; k < n; k++)
AddEdge(id[i][k], id[j][k - 1], INF);
return MaxFlow(S, T);
}
// 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
};
// BEGIN CUT HERE
int main(void) {
FoxAndCity ___test;
___test.run_test(-1);
system("pause");
}
// END CUT HERE