1. 程式人生 > >[Luogu] 洛谷 P4013 題解【數字梯形問題】

[Luogu] 洛谷 P4013 題解【數字梯形問題】

感動,終於過了(由此我發現了自己是有多麼的菜……)

其實其他幾個發題解大佬都已經把思路講的很清楚了,我就不細講了,主要是提醒大家一下

可能這一題的提交記錄中也只有我交了這麼多次,發了三篇討論,連著改了一個星期吧……

大致的思路:

    • 第一問要保證路徑互不相交,也就是不能讓一個點被經過多次

    • 是不是感覺很熟悉!是不是!沒錯,就是拆點大法!用拆點來保證只經過這個點一次即可QQwQ

    • 第二問僅不允許在路徑上相交,就沒必要拆點啦QQwQ

    • 同樣的,用流量為1來保證路徑只經過一次

    • 第三問一看……噢,這不相當於是沒有限制麼QQQQQwQ!

    • 激動的我們將流量開大並什麼也不想管

以下是我主要出問題的幾個點(求不要嘲諷):

  • memset賦負數時只能賦-1,賦其他的數會變成奇怪的負數,所以在判斷時要看他是否<0,否則就會出錯……

  • 這一題不要看範圍只有20就不開大陣列範圍,一定要開大!!,不然就會出現奇怪的錯誤,因為陣列是連續的,所以一旦爆陣列就會修改到其他幾個陣列然後就掛了……(像我就T到飛起……)

之前我改程式碼是發現……題解中沒有一篇Dinic遞迴的程式碼!

於是給大家一個並手動普度眾生

  1 #include<bits/stdc++.h>
  2 using
namespace std; 3 inline int read() 4 { 5 int f=1,w=0;char x=0; 6 while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();} 7 while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();} 8 return f*w; 9 } 10 int head[200020],cur[200020
],num_edge=-1; 11 int a[1001][1001],b[1001][1001],cnt; 12 int n,m,s,t,ans; 13 struct Edge 14 { 15 int next,to,dis,cos; 16 }edge[200020]; 17 inline void add(int from,int to,int dis,int cos) 18 { 19 edge[++num_edge].next=head[from]; 20 edge[num_edge].to=to; 21 edge[num_edge].dis=dis; 22 edge[num_edge].cos=cos; 23 head[from]=num_edge; 24 } 25 inline void clear() 26 { 27 num_edge=-1; 28 memset(head,-1,sizeof(head)); 29 ans=0; 30 } 31 int d[200000],v[200000],flo[200000]; 32 inline bool bfs() 33 { 34 memset(d,-50,sizeof(d)); 35 memset(v,0,sizeof(v)); 36 memset(flo,0,sizeof(flo)); 37 queue<int> q; 38 q.push(s); 39 d[s]=0; 40 v[s]=1;flo[s]=1; 41 while(!q.empty()) 42 { 43 int x=q.front(); 44 q.pop(); 45 v[x]=0; 46 for(int i=head[x];i!=-1;i=edge[i].next) 47 { 48 int y=edge[i].to; 49 if(edge[i].dis>0&&d[y]<d[x]+edge[i].cos) 50 { 51 d[y]=d[x]+edge[i].cos; 52 flo[y]=flo[x]+1; 53 if(!v[y]) { q.push(y); v[y]=1; } 54 } 55 } 56 } 57 if(d[t]<0) return 0; 58 else return 1; 59 } 60 int dfs(int pos,int dis) 61 { 62 if(pos==t) return dis; 63 for(int i=cur[pos];i!=-1;i=edge[i].next) 64 if(flo[edge[i].to]==flo[pos]+1&&edge[i].dis!=0&&d[edge[i].to]==d[pos]+edge[i].cos) 65 { 66 int data=dfs(edge[i].to,min(dis,edge[i].dis)); 67 if(data>0) 68 { 69 edge[i].dis-=data; 70 edge[i^1].dis+=data; 71 ans+=edge[i].cos; 72 cur[pos]=i; 73 return data; 74 } 75 } 76 return 0; 77 } 78 void Dinic() 79 { 80 while(bfs()) 81 { 82 memcpy(cur,head,sizeof(head)); 83 while(dfs(s,0x3f3f3f3f)); 84 } 85 } 86 int main(){ 87 memset(head,-1,sizeof(head)); 88 m=read(); 89 n=read(); 90 for(int i=1;i<=n;i++) 91 for(int j=1;j<=m+i-1;j++) 92 a[i][j]=read(),b[i][j]=++cnt; 93 s=0; 94 t=cnt*2+3; 95 for(int i=1;i<=m;i++) 96 add(s,b[1][i],1,0),add(b[1][i],s,0,0); 97 for(int i=1;i<n;i++) 98 for(int j=1;j<=m+i-1;j++) 99 { 100 add(b[i][j],b[i][j]+cnt,1,a[i][j]); 101 add(b[i][j]+cnt,b[i][j],0,-a[i][j]); 102 add(b[i][j]+cnt,b[i+1][j],1,0); 103 add(b[i+1][j],b[i][j]+cnt,0,0); 104 add(b[i][j]+cnt,b[i+1][j+1],1,0); 105 add(b[i+1][j+1],b[i][j]+cnt,0,0); 106 } 107 for(int i=1;i<=m+n-1;i++) 108 { 109 add(b[n][i],b[n][i]+cnt,1,a[n][i]); 110 add(b[n][i]+cnt,b[n][i],0,-a[n][i]); 111 add(b[n][i]+cnt,t,1,0); 112 add(t,b[n][i]+cnt,0,0); 113 } 114 Dinic(); 115 printf("%d\n",ans); 116 clear(); 117 for(int i=1;i<=m;i++) 118 add(s,b[1][i],1,0),add(b[1][i],s,0,0); 119 for(int i=1;i<n;i++) 120 for(int j=1;j<=m+i-1;j++) 121 { 122 add(b[i][j],b[i+1][j],1,a[i][j]); 123 add(b[i+1][j],b[i][j],0,-a[i][j]); 124 add(b[i][j],b[i+1][j+1],1,a[i][j]); 125 add(b[i+1][j+1],b[i][j],0,-a[i][j]); 126 } 127 for(int i=1;i<=m+n-1;i++) 128 { 129 add(b[n][i],t,0x3f3f3f3f,a[n][i]); 130 add(t,b[n][i],0,-a[n][i]); 131 } 132 Dinic(); 133 printf("%d\n",ans); 134 clear(); 135 for(int i=1;i<=m;i++) 136 add(s,b[1][i],1,0),add(b[1][i],s,0,0); 137 for(int i=1;i<n;i++) 138 for(int j=1;j<=m+i-1;j++) 139 { 140 add(b[i][j],b[i+1][j],0x3f3f3f3f,a[i][j]); 141 add(b[i+1][j],b[i][j],0,-a[i][j]); 142 add(b[i][j],b[i+1][j+1],0x3f3f3f3f,a[i][j]); 143 add(b[i+1][j+1],b[i][j],0,-a[i][j]); 144 } 145 for(int i=1;i<=m+n-1;i++) 146 { 147 add(b[n][i],t,0x3f3f3f3f,a[n][i]); 148 add(t,b[n][i],0,-a[n][i]); 149 } 150 Dinic(); 151 printf("%d\n",ans); 152 }