100729 F 解题报告
一套题能有两个网络流,醉了...
链接:http://codeforces.com/gym/100729/attachments/download/3754/20112012-northwestern-european-regional-contest-nwerc-2011-en.pdf
题意:
给你一块地
首先:周围一圈必须是草地
其次,每个地方可以把它从水池变为草地(代价为f),草地变成水池(代价为d)
之后水池会被建成游泳池,所以要给草地和水池之间贴瓷砖,代价为b
例如
###
#.#
###
要贴4块瓷砖,在.的四周各贴一块
所以干脆把.变成#可能会更划算
这一题是个网络流-最小割
一套题2个网络流醉了...
还有一题是100728D
S集合:
s点,所有选为#的点
T集合:
t点,所有选为.的点
注意:周围一圈直接变成#,并且统计代价
那么需要加3类边
1,次外围:s-->这个点,代价为z
理由:如果这个点建".",那么要一块额外的瓷砖
2,每个点和周围的点建立一条双向边,代价为z
理由:一个"#"一个"."要一块瓷砖
3,如果某个点是"#",那么向t连一条边代价为d(改为水池)
同理,"."的话,s-->这个点一条边代价为b
===============================
WA了好久
一开始怀疑建图错
后来怀疑网络流错
最后竟然发现是一个小函数错了..
inline int num(int x,int y) { return x*n+y; }
哦,应该是这样
inline int num(int x,int y) { return x*m+y; }
恩,总代码如下:
#include<set> #include<map> #include<list> #include<queue> #include<stack> #include<math.h> #include<string> #include<time.h> #include<bitset> #include<vector> #include<memory> #include<utility> #include<stdio.h> #include<sstream> #include<fstream> #include<iostream> #include<stdlib.h> #include<string.h> #include<algorithm> using namespace std; struct edge { int y; int weight; edge * next; edge * anti; }; const int maxn=5005; const int inf=999999999; edge * li[maxn]; int top=0; edge * new_edge() { static edge a[100005]; return &a[top++]; } edge * inserts(int x,int y,int z) { edge * t=new_edge(); t->y=y; t->weight=z; t->next=li[x]; li[x]=t; return t; } void insert_edge(int x,int y,int z) { edge * t1=inserts(x,y,z); edge * t2=inserts(y,x,0); t1->anti=t2; t2->anti=t1; } int dist[maxn]; bool bfs(int s,int t) { memset(dist,-1,sizeof(dist)); static int que[maxn]; int front=0,rail=1; que[0]=s; dist[s]=0; for (;front<rail;front++) { int now=que[front]; edge * x; for (x=li[now];x!=0;x=x->next) { if ((x->weight>0)&&(dist[x->y]==-1)) { dist[x->y]=dist[now]+1; if (x->y==t) return true; que[rail++]=x->y; } } } return false; } int max_flow(int s,int t) { int tot=0; for (;bfs(s,t);) { static edge * path[maxn]; static edge * cur[maxn]; static int pre[maxn]; memcpy(cur,li,sizeof(cur)); int now=s; for (;dist[s]!=-1;) { if (now==t) { int mini=inf; int temp; for (temp=t;temp!=s;temp=pre[temp]) { mini=min(mini,path[temp]->weight); } tot+=mini; for (temp=t;temp!=s;temp=pre[temp]) { path[temp]->weight-=mini; path[temp]->anti->weight+=mini; } now=s; } edge * x; for (x=cur[now];x!=0;x=x->next) { if ((x->weight>0)&&(dist[x->y]==dist[now]+1)) { pre[x->y]=now; path[x->y]=x; cur[now]=x; now=x->y; break; } } if (x==0) { dist[now]=-1; now=pre[now]; } } } return tot; } char a[55][55]; int n,m; inline int num(int x,int y) { return x*m+y; } int main() { #ifdef absi2011 freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif int t; scanf("%d",&t); int zu; for (zu=0;zu<t;zu++) { scanf("%d%d",&m,&n); int x,y,z; scanf("%d%d%d",&x,&y,&z); int i; for (i=0;i<n;i++) { scanf("%s",a[i]); } memset(li,0,sizeof(li)); top=0; int sum=0; for (i=0;i<m;i++) { if (a[0][i]=='.') { sum+=y; a[0][i]='#'; } if (a[n-1][i]=='.') { sum+=y; a[n-1][i]='#'; } } for (i=0;i<n;i++) { if (a[i][0]=='.') { sum+=y; a[i][0]='#'; } if (a[i][m-1]=='.') { sum+=y; a[i][m-1]='#'; } } int s=0,t=1; for (i=1;i<n-1;i++) { int j; for (j=1;j<m-1;j++) { if (i>1) { insert_edge(num(i,j),num(i-1,j),z); } else { insert_edge(s,num(i,j),z); } if (j>1) { insert_edge(num(i,j),num(i,j-1),z); } else { insert_edge(s,num(i,j),z); } if (i<n-2) { insert_edge(num(i,j),num(i+1,j),z); } else { insert_edge(s,num(i,j),z); } if (j<m-2) { insert_edge(num(i,j),num(i,j+1),z); } else { insert_edge(s,num(i,j),z); } if (a[i][j]=='#') { insert_edge(s,num(i,j),x); } else { insert_edge(num(i,j),t,y); } } } printf("%d\n",sum+max_flow(s,t)); } return 0; }