网络流专题测试-2019.03.24
24号的考试了,但是一直忘了写,今天来补一补。
defuze:http://hzwer.com/6009.html
不想写题面了,直接说怎么做吧。
其实这道题可以直接用最普通的费用流来做,找增广路时把spfa的比较函数改改就行了,但是我没想到。
可以对概率取对数,转成加法再做,就非常简单了。
注意:找增广路时设置一个精度,如果两条路径的差小于精度,就不进行松弛。否则可能会在几条费用极其相似的道路上反复增光导致超时。
1 # include <cstdio> 2 # include <iostream> 3 # include <cmath> 4 # include <cstring> 5 # include <queue> 6 # define R register int 7 8 using namespace std; 9 10 const int maxn=105; 11 const double eps=1e-7; 12 const int inf=1e9; 13 int s,t,n,m,k,h=1,firs[maxn],pre[maxn],Fl[maxn],in_que[maxn]; 14 double d[maxn],x,ans; 15 struct edge 16 { 17 int too,nex,cap; 18 double co; 19 }g[maxn*maxn]; 20 queue <int> q; 21 22 void add (int x,int y,int cap,double co) 23 { 24 g[++h].nex=firs[x]; 25 firs[x]=h; 26 g[h].too=y; 27 g[h].cap=cap; 28 g[h].co=co; 29 g[++h].nex=firs[y]; 30 firs[y]=h; 31 g[h].too=x; 32 g[h].cap=0; 33 g[h].co=-co; 34 } 35 36 bool bfs() 37 { 38 for (R i=0;i<=t;++i) d[i]=-inf; 39 double fg=d[0]; 40 q.push(s); Fl[s]=inf; d[s]=0; 41 int beg,j; 42 while(q.size()) 43 { 44 beg=q.front(); q.pop(); 45 in_que[beg]=0; 46 for (R i=firs[beg];i;i=g[i].nex) 47 { 48 j=g[i].too; 49 if(g[i].cap<=0) continue; 50 if(d[j]+eps>=d[beg]+g[i].co) continue; 51 d[j]=d[beg]+g[i].co; 52 pre[j]=i; Fl[j]=min(Fl[beg],g[i].cap); 53 if(!in_que[j]) q.push(j),in_que[j]=true; 54 } 55 } 56 return (d[t]!=fg); 57 } 58 59 void dfs() 60 { 61 int x=t,i; 62 while(x!=s) 63 { 64 i=pre[x]; 65 g[i].cap-=Fl[t]; 66 g[i^1].cap+=Fl[t]; 67 x=g[i^1].too; 68 } 69 ans+=d[t]*Fl[t]; 70 } 71 72 int main() 73 { 74 scanf("%d%d%d",&m,&n,&k); 75 s=0,t=n+m+1; 76 for (R i=1;i<=n;++i) add(s,i,1,0); 77 for (R i=1;i<=m;++i) add(i+n,t,k,0); 78 for (R i=1;i<=m;++i) 79 for (R j=1;j<=n;++j) 80 { 81 scanf("%lf",&x); 82 add(j,i+n,1,log(x)); 83 } 84 while(bfs()) 85 dfs(); 86 printf("%.4lf",exp(ans)); 87 return 0; 88 }
defuze
Asiram:http://hzwer.com/6012.html
其实就是一个最大密度子图的板子题,但是只听过没写过,而且还读错了题,爆零了。具体做法可能会在专门讲网络流那篇blog里面讲讲,也可能会咕咕咕。
1 # include <cstdio> 2 # include <iostream> 3 # include <cmath> 4 # include <cstring> 5 # include <queue> 6 # define R register int 7 # define ll long long 8 9 using namespace std; 10 11 const int maxn=502; 12 const int maxm=5003; 13 const ll inf=1e15; 14 int n,m,a[maxm],b[maxm],firs[maxn+maxm],h=1,cur[maxn+maxm],d[maxn+maxm],vis[maxn+maxm]; 15 ll w[maxn],v[maxm]; 16 int s,t; 17 queue <int> q; 18 struct edge 19 { 20 int too,nex; ll cap; 21 }g[40000]; 22 23 void add (int x,int y,ll cap) 24 { 25 g[++h].nex=firs[x]; 26 firs[x]=h; 27 g[h].too=y; 28 g[h].cap=cap; 29 g[++h].nex=firs[y]; 30 firs[y]=h; 31 g[h].too=x; 32 g[h].cap=0; 33 } 34 35 bool bfs () 36 { 37 memset(vis,0,sizeof(vis)); 38 q.push(s); vis[s]=1; 39 int beg,j; 40 while(q.size()) 41 { 42 beg=q.front(); 43 q.pop(); 44 for (R i=firs[beg];i;i=g[i].nex) 45 { 46 j=g[i].too; 47 if(g[i].cap<=0) continue; 48 if(vis[j]) continue; 49 vis[j]=1; d[j]=d[beg]+1; 50 q.push(j); 51 } 52 } 53 return vis[t]; 54 } 55 56 ll dfs (int x,ll minf) 57 { 58 if(x==t||minf==0) return minf; 59 int j; ll f,flow=0; 60 for (R &i=cur[x];i;i=g[i].nex) 61 { 62 j=g[i].too; 63 if(d[x]+1!=d[j]) continue; 64 f=dfs(j,min(minf,g[i].cap)); 65 if(f<=0) continue; 66 flow+=f; minf-=f; 67 g[i].cap-=f; g[i^1].cap+=f; 68 if(minf==0) break; 69 } 70 return flow; 71 } 72 73 ll Dinic() 74 { 75 ll ans=0; 76 while(bfs()) 77 { 78 for (R i=0;i<=t;++i) cur[i]=firs[i]; 79 ans+=dfs(s,inf); 80 } 81 return ans; 82 } 83 84 bool check (ll x) 85 { 86 ll ans=0; 87 memset(firs,0,sizeof(firs)); h=1; t=n+m+1; 88 for (R i=1;i<=n;++i) add(i+m,t,x*w[i]); 89 for (R i=1;i<=m;++i) add(s,i,v[i]),ans+=v[i]; 90 for (R i=1;i<=m;++i) add(i,a[i]+m,inf),add(i,b[i]+m,inf); 91 if(Dinic()<ans) return true; return false; 92 } 93 94 int main() 95 { 96 scanf("%d%d",&n,&m); 97 for (R i=1;i<=n;++i) scanf("%lld",&w[i]); 98 for (R i=1;i<=m;++i) 99 scanf("%d%d%lld",&a[i],&b[i],&v[i]),v[i]*=10000000; 100 ll l=1,r=1e9,mid,ans; 101 while(l<=r) 102 { 103 mid=(l+r)>>1; 104 if(check(mid)) ans=mid,l=mid+1; 105 else r=mid-1; 106 } 107 printf("%.7lf",(double)ans/10000000); 108 return 0; 109 }
Asiram
game:https://www.lydsy.com/JudgeOnline/problem.php?id=2756
考试的想了很久这道题,本来以为一定能A的,结果被多组数据坑掉了40分。为什么?因为没清空数组...
首先,如果确定了最后改到多大,那么就将每个点要加的次数作为点权,黑白染色一下,跑一遍带权最大匹配,满流则说明有解。
那么问题转化为了如何找这个最大值。
一个显然的结论是,对于格子数为偶数的棋盘,如果M是一个可行的最终值,那么M+1也是一个可行的最终值;所以对于格子数为偶数的棋盘,可以二分这个最大值。对于格子数为奇数的棋盘,不满足以上性质。
如果想要满流,一个最基本的条件是左右两部的流量相等。对于格子数为奇数的棋盘,奇偶格子的数量不同,所以说:如果最大值为M时,奇格子总共要加a次,偶格子总共要加b次,那么当最大值改变后,a-b的值也会随之发生改变。当a-b等于0时,才“有可能”满足要求。所以M可以直接算出来。注意:M不能比格子中的最大数小。
1 # include <cstdio> 2 # include <iostream> 3 # include <cmath> 4 # include <cstring> 5 # include <queue> 6 # define R register int 7 # define ll long long 8 9 using namespace std; 10 11 const int maxn=1703; 12 const ll inf=1e15; 13 int T,n,m,d[maxn],cnt,h=1,firs[maxn],vis[maxn],s,t,cur[maxn],id[maxn][maxn]; 14 ll ans,a[41][41],mx,b[41][41]; 15 struct edge 16 { 17 int too,nex; 18 ll cap; 19 }g[17004]; 20 queue <int> q; 21 22 void add (int x,int y,ll cap) 23 { 24 g[++h].nex=firs[x]; 25 firs[x]=h; 26 g[h].too=y; 27 g[h].cap=cap; 28 g[++h].nex=firs[y]; 29 firs[y]=h; 30 g[h].too=x; 31 g[h].cap=0; 32 } 33 34 bool bfs () 35 { 36 memset(vis,0,sizeof(vis)); 37 q.push(s); vis[s]=1; d[s]=0; 38 int beg,j; 39 while(q.size()) 40 { 41 beg=q.front(); 42 q.pop(); 43 for (R i=firs[beg];i;i=g[i].nex) 44 { 45 j=g[i].too; 46 if(g[i].cap<=0) continue; 47 if(vis[j]) continue; 48 vis[j]=1; d[j]=d[beg]+1; 49 q.push(j); 50 } 51 } 52 return vis[t]; 53 } 54 55 ll dfs (int x,ll minf) 56 { 57 if(x==t||minf==0) return minf; 58 int j; ll f,flow=0; 59 for (R &i=cur[x];i;i=g[i].nex) 60 { 61 j=g[i].too; 62 if(d[x]+1!=d[j]) continue; 63 f=dfs(j,min(minf,g[i].cap)); 64 if(f<=0) continue; 65 flow+=f; minf-=f; 66 g[i].cap-=f; g[i^1].cap+=f; 67 if(minf==0) break; 68 } 69 return flow; 70 } 71 72 ll Dinic() 73 { 74 ll ans=0; 75 while(bfs()) 76 { 77 for (R i=0;i<=t;++i) cur[i]=firs[i]; 78 ans+=dfs(s,inf); 79 } 80 return ans; 81 } 82 83 ll check (ll mx) 84 { 85 memset(firs,0,sizeof(firs)); 86 h=1; 87 ll ans=0,max_flow; 88 for (R i=1;i<=n;++i) 89 for (R j=1;j<=m;++j) 90 { 91 a[i][j]=mx-b[i][j]; 92 if((i+j)%2) 93 { 94 ans+=a[i][j]; 95 add(s,id[i][j],a[i][j]); 96 if(id[i+1][j]) add(id[i][j],id[i+1][j],inf); 97 if(id[i][j+1]) add(id[i][j],id[i][j+1],inf); 98 } 99 else 100 { 101 add(id[i][j],t,a[i][j]); 102 if(id[i+1][j]) add(id[i+1][j],id[i][j],inf); 103 if(id[i][j+1]) add(id[i][j+1],id[i][j],inf); 104 } 105 } 106 max_flow=Dinic(); 107 if(max_flow==ans) return ans; 108 return -1; 109 } 110 111 int main() 112 { 113 scanf("%d",&T); 114 while(T--) 115 { 116 scanf("%d%d",&n,&m); 117 mx=0; 118 s=0,t=n*m+1; 119 ans=0; cnt=0; 120 memset(id,0,sizeof(id)); 121 for (R i=1;i<=n;++i) 122 for (R j=1;j<=m;++j) 123 { 124 id[i][j]=++cnt; 125 scanf("%lld",&b[i][j]); 126 mx=max(b[i][j],mx); 127 } 128 ll t1=0,t2=0; 129 for (R i=1;i<=n;++i) 130 for (R j=1;j<=m;++j) 131 if((i+j)%2) t2+=mx-b[i][j]; 132 else t1+=mx-b[i][j]; 133 if(n*m%2) 134 { 135 if(t2<t1) { puts("-1"); continue; } 136 mx+=t2-t1; 137 ans=check(mx); 138 } 139 else 140 { 141 ll l=mx,r=mx+1e9,mid,t; ans=-1; 142 if(t1!=t2) { puts("-1"); continue; } 143 while(l<=r) 144 { 145 mid=(l+r)>>1; 146 t=check(mid); 147 if(t!=-1) r=mid-1; 148 else l=mid+1; 149 if(t==-1) continue; 150 if(ans==-1) ans=t; else ans=min(ans,t); 151 } 152 } 153 printf("%lld\n",ans); 154 } 155 return 0; 156 }
game
---shzr
原文地址:https://www.cnblogs.com/shzr/p/10599196.html