|
分析:类似这样的题做得挺多,看完不久,便想到可能是最小割的应用,然后就是长久的挣扎,下面就说说别人的构图吧,我自己还没完全明白= = 看了很多人的代码,就下面这个构图简单,而且明白一点点
首先将所有格子黑白涂色,将每个格子分成两个节点,然后虚拟源点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