bzoj2055: 80人环游世界(可行流)
表示完全看不懂最小费用可行流……
据某大佬说
我们考虑拆点,然后进行如下连边
$s$向$a_i$连边,权值$0$,容量$[0,m]$
$a_i$向$a_i'$连边,权值$0$容量$[v_i,v_i]$
如果存在边$(i,j)$,则连边$a_i'->a_i$,权值为$w_{i,j}$,容量$[0,m]$
$a_i'$向$t$连边,权值$0$,容量$[0,m]$
$t$向$t'$连边,权值$0$容量$[0,m]$
然后跑个最小费用可行流
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #define inf 0x3f3f3f3f 7 using namespace std; 8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 9 char buf[1<<21],*p1=buf,*p2=buf; 10 inline int read(){ 11 #define num ch-'0' 12 char ch;bool flag=0;int res; 13 while(!isdigit(ch=getc())) 14 (ch=='-')&&(flag=true); 15 for(res=num;isdigit(ch=getc());res=res*10+num); 16 (flag)&&(res=-res); 17 #undef num 18 return res; 19 } 20 const int N=505,M=500005; 21 int head[N],Next[M],ver[M],edge[M],flow[M],tot=1; 22 inline void add(int u,int v,int e,int f){ 23 ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e,flow[tot]=f; 24 ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=-e,flow[tot]=0; 25 } 26 int dis[N],vis[N],cur[N],S,T,ans,s,t,kt,n,m; 27 queue<int> q; 28 bool spfa(){ 29 memset(dis,-1,sizeof(dis)); 30 memset(vis,0,sizeof(vis)); 31 memcpy(cur,head,sizeof(head)); 32 q.push(T),dis[T]=0,vis[T]=1; 33 while(!q.empty()){ 34 int u=q.front();q.pop();vis[u]=0; 35 for(int i=head[u];i;i=Next[i]) 36 if(flow[i^1]){ 37 int v=ver[i],e=edge[i]; 38 if(dis[v]<0||dis[v]>dis[u]-e){ 39 dis[v]=dis[u]-e; 40 if(!vis[v]) vis[v]=1,q.push(v); 41 } 42 } 43 } 44 return ~dis[S]; 45 } 46 int dfs(int u,int limit){ 47 if(!limit||u==T) return limit; 48 int fl=0,f;vis[u]=1; 49 for(int i=cur[u];i;cur[u]=i=Next[i]){ 50 int v=ver[i]; 51 if(dis[v]==dis[u]-edge[i]&&!vis[v]&&(f=dfs(v,min(limit,flow[i])))){ 52 fl+=f,limit-=f; 53 ans+=f*edge[i]; 54 flow[i]-=f,flow[i^1]+=f; 55 if(!limit) break; 56 } 57 } 58 vis[u]=0; 59 return fl; 60 } 61 void zkw(){ 62 while(spfa()) dfs(S,inf); 63 } 64 int main(){ 65 //freopen("testdata.in","r",stdin); 66 n=read(),m=read(),s=2*n+1,t=s+1,kt=t+1,S=kt+1,T=S+1; 67 for(int i=1;i<=n;++i){ 68 int x=read(); 69 add(S,i+n,0,x),add(i,T,0,x), 70 add(s,i,0,m),add(i+n,t,0,m); 71 } 72 add(t,kt,0,m),add(kt,s,0,inf); 73 for(int i=1;i<=n;++i) 74 for(int j=i+1;j<=n;++j){ 75 int x=read(); 76 if(~x) add(n+i,j,x,inf); 77 } 78 zkw(); 79 printf("%d\n",ans); 80 return 0; 81 }
深深地明白自己的弱小