1. 程式人生 > 實用技巧 >Matrix Again HDU - 3376 (最大費用最大流+拆點)

Matrix Again HDU - 3376 (最大費用最大流+拆點)

Practice link:https://vjudge.net/problem/HDU-3376

題意:給你一個 n*n 的矩陣,每個點有自身的權值,從左上角向右下角走只能向右或向下,從右下角向左上角走只能向左或向上,問你從左上角走向右下角再從右下角走向左上角且每個點只能走一次,問你最大權值之和是多少。

思路:首先從右下角到左上角的過程可以轉化為從左上角到右下角,那麼問題就變成了從左上角到右下角的兩條沒有重複點的路徑的最大權值和。然後看到是走矩陣且要求權值之和最大且每個格子只能走一次,就想到最大費用最大流。首先建立超級源點和超級匯點,源點到左上角的點的流量為2,費用為 0,右下角的點到匯點的流量為 2 ,費用為 0

,由於每個點只能走一次,那麼我們就進行拆點,即把點 k 拆成兩個點 k1 和 k2,這兩個點之間的流量為 1 ,費用為點 k 的權值(除了左上角和右下角的兩個點的流量需要為 2)。其餘可以聯通的點之間的流量為 1 ,費用為 0 即可。

最後跑一遍最大費用最大流,又因為左上角和右下角的點經過了兩次,最後答案要減去這兩個點的權值。

程式碼:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<iostream>
  5 #include<string
> 6 #include<vector> 7 #include<stack> 8 #include<bitset> 9 #include<cstdlib> 10 #include<cmath> 11 #include<set> 12 #include<list> 13 #include<deque> 14 #include<map> 15 #include<queue> 16 #define ll long long 17 #define MOD 998244353 18
#define INF 0x3f3f3f3f 19 #define mem(a,x) memset(a,x,sizeof(a)) 20 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 21 using namespace std; 22 23 const int maxn = 800000; 24 25 bool vis[maxn]; 26 int n,m,s,t; 27 int dis[maxn],pre[maxn],last[maxn],flow[maxn],maxflow,maxcost; 28 29 struct node{ 30 int to,nxt,flow,dis; //flow流量 dis花費 31 }edge[4*maxn]; 32 int head[4*maxn],cnt=0; 33 34 void addl(int u,int v,int flow,int dis) 35 { 36 edge[cnt].to=v; 37 edge[cnt].flow=flow; 38 edge[cnt].dis=dis; 39 edge[cnt].nxt=head[u]; 40 head[u]=cnt++; 41 } 42 43 bool spfa(int s,int t) 44 { 45 for(int i=0;i<=2*n*n+1;i++){ 46 dis[i]=-1; 47 flow[i]=INF; 48 vis[i]=0; 49 } 50 queue<int>q; 51 q.push(s); 52 vis[s]=1; 53 dis[s]=0; 54 pre[t]=-1; 55 while(!q.empty()){ 56 int now=q.front(); 57 q.pop(); 58 vis[now]=0; 59 for(int i=head[now];i!=-1;i=edge[i].nxt) 60 { 61 if(edge[i].flow>0&&dis[edge[i].to]<dis[now]+edge[i].dis) 62 { 63 dis[edge[i].to]=dis[now]+edge[i].dis; 64 pre[edge[i].to]=now; 65 last[edge[i].to]=i; 66 flow[edge[i].to]=min(flow[now],edge[i].flow); 67 if(!vis[edge[i].to]) 68 { 69 vis[edge[i].to]=1; 70 q.push(edge[i].to); 71 } 72 } 73 } 74 } 75 return pre[t]!=-1; 76 } 77 void MCMF() 78 { 79 while(spfa(s,t)) 80 { 81 int now=t; 82 maxflow+=flow[t]; 83 maxcost+=flow[t]*dis[t]; 84 while(now!=s) 85 { 86 edge[last[now]].flow-=flow[t]; 87 edge[last[now]^1].flow+=flow[t]; 88 now=pre[now]; 89 } 90 } 91 } 92 int mp[605][605]; 93 int main() 94 { 95 while (scanf("%d",&n)!=EOF) { 96 mem(head,-1); 97 mem(pre,-1); 98 cnt=0; 99 maxflow=0; 100 maxcost=0; 101 s=0; 102 t=2*n*n+1; 103 addl(s,1,2,0); 104 addl(1,s,0,0); 105 for(int i=1;i<=n;i++){ 106 for(int j=1;j<=n;j++){ 107 scanf("%d",&mp[i][j]); 108 int num=(i-1)*n+j; 109 if(i==j&&(num==1||num==n*n)){ 110 addl(num,num+n*n,2,mp[i][j]); 111 addl(num+n*n,num,0,-mp[i][j]); 112 }else{ 113 addl(num+n*n,num,0,-mp[i][j]); 114 addl(num,num+n*n,1,mp[i][j]); 115 } 116 if(i+1<=n){ 117 addl(num+n*n,i*n+j,1,0); 118 addl(i*n+j,num+n*n,0,0); 119 } 120 if(j+1<=n){ 121 addl(num+n*n,num+1,1,0); 122 addl(num+1,num+n*n,0,0); 123 } 124 } 125 } 126 addl(2*n*n,t,2,0); 127 addl(t,2*n*n,0,0); 128 MCMF(); 129 printf("%d\n",maxcost-mp[1][1]-mp[n][n]); 130 } 131 return 0; 132 }