P2045 方格取数加强版
P2045 方格取数加强版
题目描述
给出一个
Solution:
有且仅有一点思维难度的费用题,我们考虑拆点来维护每个格子上的数只能被取一次和流量限制:
然后再按题意将
Code:
#include<bits/stdc++.h> const int M=55; const int N=M*M*2; const int inf=1e9; using namespace std; int a[M][M]; int n,m,S,T,ans,cnt=1; struct Edge{ int to,w,fl,nxt; }e[N<<2];int head[N]; inline void add(int x,int y,int w,int fl) { e[++cnt]={y,w,fl,head[x]};head[x]=cnt; e[++cnt]={x,-w,0,head[y]};head[y]=cnt; } inline int id(int i,int j){return (i-1)*n+j;} inline int idd(int i,int j){return n*n+id(i,j);} int dis[N],dl[N],flow[N],pre[N]; inline void init() { for(int u=0;u<=T;u++)dis[u]=-inf,flow[u]=0; } queue<int> Q; bool spfa(int s,int t) { init();flow[s]=m;dis[s]=0; Q.push(s); while(!Q.empty()) { int u=Q.front();Q.pop();dl[u]=0; for(int i=head[u],v,w,fl;i;i=e[i].nxt) { v=e[i].to,w=e[i].w,fl=e[i].fl; if(fl&&dis[v]<dis[u]+w) { dis[v]=dis[u]+w;flow[v]=min(fl,flow[u]); if(!dl[v])Q.push(v);pre[v]=i; } } } return dis[t]!=-inf; } void dinic() { while(spfa(S,T)) { int now=T,id,res=0; ans+=dis[T]; while(now!=S) { id=pre[now];e[id].fl--;e[id^1].fl++;now=e[id^1].to; } } } void work() { cin>>n>>m;S=1,T=idd(n,n); for(int i=1,x;i<=n;i++)for(int j=1;j<=n;j++) { scanf("%d",&x); add(id(i,j),idd(i,j),x,1); add(id(i,j),idd(i,j),0,m-1); if(i+1<=n)add(idd(i,j),id(i+1,j),0,m); if(j+1<=n)add(idd(i,j),id(i,j+1),0,m); } dinic(); cout<<ans; } int main() { //freopen("P2045.in","r",stdin);freopen("P2045.out","w",stdout); work(); return 0; }