努力刷网络流找感觉ing……
这其实是一个费用流,拆点,流量为1,费用为val。
求其最大费用流,可以转化为边权相反,求最小费用流的相反数。
看代码:
#include<bits/stdc++.h> using namespace std; #define inf 1e9 int val[100][100]; int n,k; const int maxn=1e5+10; int beg[maxn],nex[maxn],to[maxn],w[maxn],f[maxn],e; inline void add(int x,int y,int z,int c){ nex[e]=beg[x];beg[x]=e; to[e]=y;w[e]=c;f[e]=z;e++; } int flow[maxn],dis[maxn],vis[maxn]; queue<int>q; int las[maxn],pos[maxn]; inline int spfa(){ memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); while(!q.empty())q.pop(); dis[0]=0; flow[0]=inf; vis[0]=1; q.push(0); while(!q.empty()){ int x=q.front(); q.pop(); vis[x]=0; for(int i=beg[x];~i;i=nex[i]){ int t=to[i]; if(f[i]&&dis[t]>dis[x]+w[i]){ dis[t]=dis[x]+w[i]; las[t]=x; pos[t]=i; flow[t]=min(flow[x],f[i]); if(!vis[t]){ vis[t]=1; q.push(t); } } } } return dis[2*n*n+1]<=1000000; } int main(){ memset(beg,-1,sizeof(beg)); cin>>n>>k; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>val[i][j]; add(0,1,k,0); add(1,0,0,0); add(2*n*n,2*n*n+1,k,0); add(2*n*n+1,2*n*n,0,0); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ add((i-1)*n+j,(i-1)*n+j+n*n,1,-val[i][j]); add((i-1)*n+j+n*n,(i-1)*n+j,0,val[i][j]); add((i-1)*n+j,(i-1)*n+j+n*n,inf,0); add((i-1)*n+j+n*n,(i-1)*n+j,0,0); if(i<n){ add((i-1)*n+j+n*n,i*n+j,inf,0); add(i*n+j,(i-1)*n+j+n*n,0,0); } if(j<n){ add((i-1)*n+j+n*n,(i-1)*n+j+1,inf,0); add((i-1)*n+j+1,(i-1)*n+j+n*n,0,0); } } int ans=0; while(spfa()){ ans-=flow[2*n*n+1]*dis[2*n*n+1]; int tmp=2*n*n+1; while(tmp!=0){ f[pos[tmp]]-=flow[2*n*n+1]; f[pos[tmp]^1]+=flow[2*n*n+1]; tmp=las[tmp]; } } printf("%d ",ans); return 0; }
深深地感到自己的弱小。