【P2405】方格取数问题加强版(费用流)
考虑如何建图。还是老样子先拆点,然后把每两个点之间连接两条边,一条流量为1,费用为-点权,处理是否走这个点。一条流量无限,没有费用,因为哪怕一个点选过了,它的地方还是可以重复走过去的。 然后把经由一个点能到达的另一个点连边。因为要走k次,所以由s向1号点入点连边,n号点出点向t连边,流量为k,费用为0。然后一边最小费用最大流板子即可。 然后发现这些个题解里没有用原始对偶来实现的,所以弱弱的拿出自己代码,勉强还是能在最优解第一页里的,膜拜那些50ms都不到就跑完的dalao们。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #define ll long long #define rp (i-1)*n+j #define cp (i-1)*n+j+n*n #define inf 50000000 #define re register using namespace std; struct po { int from,to,dis,nxt,w; }edge[250001]; int head[250001],cur[1000001],dep[60001],n,m,s,t,u,num=-1,x,y,l,tot,sum,k; int dis[6001],b[6001],xb[20001],flow[20001],a[55][55]; inline int read() { int x=0,c=1; char ch=' '; while((ch>'9'||ch<'0')&&ch!='-')ch=getchar(); while(ch=='-')c*=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar(); return x*c; } inline void add_edge(int from,int to,int w,int dis) { edge[++num].nxt=head[from]; edge[num].to=to; edge[num].w=w; edge[num].dis=dis; head[from]=num; } inline void add(int from,int to,int w,int dis) { add_edge(from,to,w,dis); add_edge(to,from,0,-dis); } inline bool spfa() { memset(b,0,sizeof(b)); memset(dis,100,sizeof(dis)); deque<int> q; while(!q.empty()) q.pop_back(); dis[t]=0;b[t]=1; q.push_back(t); while(!q.empty()) { int u=q.front(); q.pop_front(); b[u]=0; for(re int i=head[u];i!=-1;i=edge[i].nxt) { int v=edge[i].to; if(edge[i^1].w>0&&dis[v]>dis[u]-edge[i].dis) { dis[v]=dis[u]-edge[i].dis; if(!b[v]) { b[v]=1; if(!q.empty()&&dis[v]<dis[q.front()]) q.push_front(v); else q.push_back(v); } } } } return dis[s]<inf; } inline int dfs(int u,int low) { if(u==t) { b[t]=1; return low; } int diss=0; b[u]=1; for(re int i=head[u];i!=-1;i=edge[i].nxt) { int v=edge[i].to; if(!b[v]&&edge[i].w!=0&&dis[v]==dis[u]-edge[i].dis) { int check=dfs(v,min(low,edge[i].w)); if(check>0) { tot+=check*edge[i].dis; low-=check; diss+=check; edge[i].w-=check; edge[i^1].w+=check; if(low==0) break; } } } return diss; } inline void max_flow() { int ans=0; while(spfa()) { b[t]=1; while(b[t]==1) { memset(b,0,sizeof(b)); ans=dfs(s,inf); } } } int main() { memset(head,-1,sizeof(head)); n=read();k=read(); for(re int i=1;i<=n;i++) for(re int j=1;j<=n;j++) a[i][j]=read(); s=0;t=n*n*2+1; add(s,1,k,0);add(n*n*2,t,k,0); for(re int i=1;i<=n;i++) for(re int j=1;j<=n;j++) { add(rp,cp,1,-a[i][j]); add(rp,cp,inf,0); if(i<n) add(cp,rp+n,inf,0); if(j<n) add(cp,rp+1,inf,0); } max_flow(); cout<<-tot; }
对于作者转载文章,欢迎继续转载。
对于作者原创文章,请注明出处之后转载。