|
分析:类似这样的题做得挺多,看完不久,便想到可能是最小割的应用,然后就是长久的挣扎,下面就说说别人的构图吧,我自己还没完全明白= = 看了很多人的代码,就下面这个构图简单,而且明白一点点
首先将所有格子黑白涂色,将每个格子分成两个节点,然后虚拟源点S和汇点T,对于黑色格子i,建两条边,S到i,容量为花费,i到i'容量为收益,对于白色格子j,也是两条边,j到T,容量为花费,j'到j容量为收益,对于i与j相邻的,也建立两条边,i到j',和i'到j,容量都是无穷,这样做最大流,答案就是所有收益-最大流的值
仔细推敲了下,这个模型是假设取了所有格子的收益,然后怎样摆放石子,使得花费最小,也就是这个模型就是求最小花费的,中间两条容量为收益的边正好限制花费不超过收益,在这个前提下,使得总花费最小,这就是我大概的理解
希望有谁会这道题,指导我下
PS:由于比赛时做完一题就剩20分钟,弱菜无力。。。看完这题就剩6分钟了,立马贴了个模板,随便构图,最后样例都调不出来,本来后悔不应该中途放松的,比赛后才发现就算做了我也做不出来,这题不是简单题 T_T
冥思苦想了两天,还是没想出怎样构图,无奈看了别人的代码,还是懵懵懂懂,不过这回ID变黄了,贴下来当纪念吧,嘿嘿
代码:
// BEGIN CUT HERE // END CUT HERE #line 5 "SurroundingGame.cpp" #include<cstdlib> #include<cctype> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<vector> #include<string> #include<iostream> #include<sstream> #include<map> #include<set> #include<queue> #include<stack> #include<fstream> #include<numeric> #include<iomanip> #include<bitset> #include<list> #include<stdexcept> #include<functional> #include<utility> #include<ctime> using namespace std; #define PB push_back #define MP make_pair #define REP(i,n) for(i=0;i<(n);++i) #define FOR(i,l,h) for(i=(l);i<=(h);++i) #define FORD(i,h,l) for(i=(h);i>=(l);--i) typedef vector<int> VI; typedef vector<string> VS; typedef vector<double> VD; typedef long long LL; typedef pair<int,int> PII; const int mm=1000000; const int mn=22222; const int oo=1000000000; int node,src,dest,edge; int reach[mm],flow[mm],next[mm]; int head[mn],work[mn],dis[mn],q[mn]; inline int min(int a,int b) { return a<b?a:b; } inline void prepare(int _node,int _src,int _dest) { node=_node,src=_src,dest=_dest; for(int i=0;i<node;++i)head[i]=-1; edge=0; } inline void addedge(int u,int v,int c) { reach[edge]=v,flow[edge]=c,next[edge]=head[u],head[u]=edge++; reach[edge]=u,flow[edge]=0,next[edge]=head[v],head[v]=edge++; } bool Dinic_bfs() { int i,u,v,l,r=0; for(i=0;i<node;++i)dis[i]=-1; dis[q[r++]=src]=0; for(l=0;l<r;++l) for(i=head[u=q[l]];i>=0;i=next[i]) if(flow[i]&&dis[v=reach[i]]<0) { dis[q[r++]=v]=dis[u]+1; if(v==dest)return 1; } return 0; } int Dinic_dfs(int u,int exp) { if(u==dest)return exp; for(int &i=work[u],v,tmp;i>=0;i=next[i]) if(flow[i]&&dis[v=reach[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0) { flow[i]-=tmp; flow[i^1]+=tmp; return tmp; } return 0; } int Dinic_flow() { int i,ret=0,delta; while(Dinic_bfs()) { for(i=0;i<node;++i)work[i]=head[i]; while(delta=Dinic_dfs(src,oo))ret+=delta; } return ret; } int get(char a) { if(a>='0'&&a<='9')return a-'0'; if(a>='a'&&a<='z')return a-'a'+10; if(a>='A'&&a<='Z')return a-'A'+36; return 0; } int dx[]={0,0,-1,1}; int dy[]={-1,1,0,0}; class SurroundingGame { public: int maxScore(vector <string> cost, vector <string> benefit) { int i,j,k,x,y,n=cost.size(),m=cost[0].size(),sum=0; prepare(n*m*2+2,0,n*m*2+1); for(i=0;i<n;++i) for(j=0;j<m;++j) { sum+=get(benefit[i][j]); if((i+j)%2) { addedge(src,i*m+j+1,get(cost[i][j])); addedge(i*m+j+1,n*m+i*m+j+1,get(benefit[i][j])); } else { addedge(n*m+i*m+j+1,i*m+j+1,get(benefit[i][j])); addedge(i*m+j+1,dest,get(cost[i][j])); } for(k=0;k<4;++k) { x=i+dx[k]; y=j+dy[k]; if(x<0||x>=n||y<0||y>=m)continue; if((i+j)%2)addedge(n*m+i*m+j+1,x*m+y+1,oo); else addedge(x*m+y+1,n*m+i*m+j+1,oo); } } sum-=Dinic_flow(); return sum; } // 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(); } 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[] = {"21","12"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); string Arr1[] = {"21","12"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 4; verify_case(0, Arg2, maxScore(Arg0, Arg1)); } void test_case_1() { string Arr0[] = {"ZZ","ZZ"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); string Arr1[] = {"11","11"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 0; verify_case(1, Arg2, maxScore(Arg0, Arg1)); } void test_case_2() { string Arr0[] = {"XXX","XXX","XXX"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); string Arr1[] = {"aaa","aZa","aaa"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 2; verify_case(2, Arg2, maxScore(Arg0, Arg1)); } void test_case_3() { string Arr0[] = {"asam","atik"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); string Arr1[] = {"123A","45BC"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 71; verify_case(3, Arg2, maxScore(Arg0, Arg1)); } void test_case_4() { string Arr0[] = {"IIIIIIII", "IIWWWWII", "IIWIIIII", "IIWIIIII", "IIWWWWII", "IIIIIWII", "IIIIIWII", "IIWWWWII", "IIIIIIII"} ; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); string Arr1[] = {"IIIIIIII", "II0000II", "II0II0II", "II0II0II", "II0000II", "II0II0II", "II0II0II", "II0000II", "IIIIIIII"} ; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 606; verify_case(4, Arg2, maxScore(Arg0, Arg1)); } // END CUT HERE }; // BEGIN CUT HERE int main() { SurroundingGame ___test; ___test.run_test(-1); return 0; } // END CUT HERE