Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 737 Accepted Submission(s): 305
php
大體題意:ios
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int VM=101000; const int EM=500100; const int INF=0x3f3f3f3f; struct Edge{ int to,nxt; int cap; }edge[EM<<1]; int n,m,k,cnt,head[VM],map[110][110]; int dep[VM],gap[VM],cur[VM],aug[VM],pre[VM]; void addedge(int cu,int cv,int cw){ edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu]; head[cu]=cnt++; edge[cnt].to=cu; edge[cnt].cap=0; edge[cnt].nxt=head[cv]; head[cv]=cnt++; } int src,des; int SAP(int n){ int max_flow=0,u=src,v; int id,mindep; aug[src]=INF; pre[src]=-1; memset(dep,0,sizeof(dep)); memset(gap,0,sizeof(gap)); gap[0]=n; for(int i=0;i<=n;i++) cur[i]=head[i]; // 初始化當前弧爲第一條弧 while(dep[src]<n){ int flag=0; if(u==des){ max_flow+=aug[des]; for(v=pre[des];v!=-1;v=pre[v]){ // 路徑回溯更新殘留網絡 id=cur[v]; edge[id].cap-=aug[des]; edge[id^1].cap+=aug[des]; aug[v]-=aug[des]; // 修改可增廣量,之後會用到 if(edge[id].cap==0) // 不回退到源點,僅回退到容量爲0的弧的弧尾 u=v; } } for(int i=cur[u];i!=-1;i=edge[i].nxt){ v=edge[i].to; // 從當前弧開始查找容許弧 if(edge[i].cap>0 && dep[u]==dep[v]+1){ // 找到容許弧 flag=1; pre[v]=u; cur[u]=i; aug[v]=min(aug[u],edge[i].cap); u=v; break; } } if(!flag){ if(--gap[dep[u]]==0) /* gap優化,層次樹出現斷層則結束算法 */ break; mindep=n; cur[u]=head[u]; for(int i=head[u];i!=-1;i=edge[i].nxt){ v=edge[i].to; if(edge[i].cap>0 && dep[v]<mindep){ mindep=dep[v]; cur[u]=i; // 修改標號的同時修改當前弧 } } dep[u]=mindep+1; gap[dep[u]]++; if(u!=src) // 回溯繼續尋找容許弧 u=pre[u]; } } return max_flow; } int main(){ //freopen("input.txt","r",stdin); while(~scanf("%d%d%d",&n,&m,&k)){ cnt=0; memset(head,-1,sizeof(head)); src=0; des=n*m+1; int sum=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d",&map[i][j]); sum+=map[i][j]; } int x,y; while(k--){ scanf("%d%d",&x,&y); if((x+y)%2==0) addedge(src,(x-1)*m+y,INF); else addedge((x-1)*m+y,des,INF); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ int tmp=(i-1)*m+j; if((i+j)%2==0) addedge(src,tmp,map[i][j]); else addedge(tmp,des,map[i][j]); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if((i+j)%2==0){ int tmp=(i-1)*m+j; if(i>1) addedge(tmp,tmp-m,2*(map[i][j]&map[i-1][j])); if(i<n) addedge(tmp,tmp+m,2*(map[i][j]&map[i+1][j])); if(j>1) addedge(tmp,tmp-1,2*(map[i][j]&map[i][j-1])); if(j<m) addedge(tmp,tmp+1,2*(map[i][j]&map[i][j+1])); } printf("%d\n",sum-SAP(des+1)); } return 0; }
上面用SAP算法,只用了78ms,而下面的Dinic用了1600ms,Orz。。。。。。。。。算法
Dinic():網絡
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int VM=101000; const int EM=500100; const int INF=0x3f3f3f3f; struct Edge{ int to,nxt; int cap; }edge[EM<<1]; int n,m,k,cnt,head[VM],src,des; int map[110][110],dep[VM]; //dep[i]表示當前點到起點src的層數 void addedge(int cu,int cv,int cw){ edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu]; head[cu]=cnt++; edge[cnt].to=cu; edge[cnt].cap=0; edge[cnt].nxt=head[cv]; head[cv]=cnt++; } int BFS(){ // 從新建圖(按層數建圖) queue<int> q; while(!q.empty()) q.pop(); memset(dep,-1,sizeof(dep)); dep[src]=0; q.push(src); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(edge[i].cap>0 && dep[v]==-1){ // 若是能夠到達且尚未訪問 dep[v]=dep[u]+1; q.push(v); } } } return dep[des]!=-1; } int DFS(int u,int minx){ // 查找路徑上的最小的流量 if(u==des) return minx; int tmp; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(edge[i].cap>0 && dep[v]==dep[u]+1 && (tmp=DFS(v,min(minx,edge[i].cap)))){ edge[i].cap-=tmp; //正向減小 edge[i^1].cap+=tmp; //反向增長 return tmp; } } return 0; } int Dinic(){ int ans=0,tmp; while(BFS()){ while(1){ tmp=DFS(src,INF); if(tmp==0) break; ans+=tmp; } } return ans; } int main(){ //freopen("input.txt","r",stdin); while(~scanf("%d%d%d",&n,&m,&k)){ cnt=0; memset(head,-1,sizeof(head)); src=0; des=n*m+1; int sum=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d",&map[i][j]); sum+=map[i][j]; } int x,y; while(k--){ scanf("%d%d",&x,&y); if((x+y)%2==0) addedge(src,(x-1)*m+y,INF); else addedge((x-1)*m+y,des,INF); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ int tmp=(i-1)*m+j; if((i+j)%2==0) addedge(src,tmp,map[i][j]); else addedge(tmp,des,map[i][j]); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if((i+j)%2==0){ int tmp=(i-1)*m+j; if(i>1) addedge(tmp,tmp-m,2*(map[i][j]&map[i-1][j])); if(i<n) addedge(tmp,tmp+m,2*(map[i][j]&map[i+1][j])); if(j>1) addedge(tmp,tmp-1,2*(map[i][j]&map[i][j-1])); if(j<m) addedge(tmp,tmp+1,2*(map[i][j]&map[i][j+1])); } printf("%d\n",sum-Dinic()); } return 0; }
下面的EK算法直接超時了,暫且不知道是否是還有什麼優化,。。。。。。。app
EK():優化
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int VM=101000; const int EM=500100; const int INF=0x3f3f3f3f; struct Edge{ int to,nxt; int cap; }edge[EM<<1]; int n,m,k,cnt,head[VM],max_flow; //max_flow是最大流 int map[110][110],flow[110][110]; // map[i][j]是每條邊的容量,flow[i][j]是每條邊的流量 int res[VM],pre[VM]; //res[]是每一個點的剩餘流量,pre[]是每一個點的父親 void addedge(int cu,int cv,int cw){ edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu]; head[cu]=cnt++; edge[cnt].to=cu; edge[cnt].cap=0; edge[cnt].nxt=head[cv]; head[cv]=cnt++; } int EK(int src,int des){ max_flow=0; queue<int> q; while(!q.empty()) q.pop(); memset(flow,0,sizeof(flow)); //最開始每條邊的流量都是0 while(1){ memset(res,0,sizeof(res)); //殘餘流量得變0,一開始全部點都沒流入對吧 res[src]=INF; //源點嘛,剩餘流量無限是必須的... q.push(src); //從源點開始進行BFS找增廣路 while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].nxt){ //遍歷全部點,找可行邊 int v=edge[i].to; if(!res[v] && edge[i].cap>flow[u][v]){ //該點剩餘流量爲0 且 容量大於流量,也就是找到了新的結點 pre[v]=u; //找到新結點,父節點得記錄一下吧 q.push(v); res[v]=min(res[u],edge[i].cap-flow[u][v]); //若是u的剩餘流量能填滿uv就填滿,不能的話就把u這點的流量所有流向uv } } } if(res[des]==0) //若是當前已是最大流,匯點沒有殘餘流量 return max_flow; for(int u=des;u!=src;u=pre[u]){ //若是還能增廣,那麼回溯,從匯點往回更新每條走過的邊的流量 flow[pre[u]][u]+=res[des]; //更新正向流量 (注意這裏更新的是流量,而不是容量) flow[u][pre[u]]-=res[des]; //更新反向流量 } max_flow+=res[des]; } } int main(){ //freopen("input.txt","r",stdin); while(~scanf("%d%d%d",&n,&m,&k)){ cnt=0; memset(head,-1,sizeof(head)); int src=0, des=n*m+1; int sum=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d",&map[i][j]); sum+=map[i][j]; } int x,y; while(k--){ scanf("%d%d",&x,&y); if((x+y)%2==0) addedge(src,(x-1)*m+y,INF); else addedge((x-1)*m+y,des,INF); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ int tmp=(i-1)*m+j; if((i+j)%2==0) addedge(src,tmp,map[i][j]); else addedge(tmp,des,map[i][j]); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if((i+j)%2==0){ int tmp=(i-1)*m+j; if(i>1) addedge(tmp,tmp-m,2*(map[i][j]&map[i-1][j])); if(i<n) addedge(tmp,tmp+m,2*(map[i][j]&map[i+1][j])); if(j>1) addedge(tmp,tmp-1,2*(map[i][j]&map[i][j-1])); if(j<m) addedge(tmp,tmp+1,2*(map[i][j]&map[i][j+1])); } printf("%d\n",sum-EK(src,des)); } return 0; }