【Gym】101194J Mr.Panda and TubeMaster

来源:互联网 发布:linux ip地址映射 编辑:程序博客网 时间:2024/06/08 18:35

看到题的第一想法:上下界最大费用循环流

后来问了下同学,发现可以如下表示:
每个格子拆成入和出,
假如这个格子没有限制必须走,那么它就可以不参与匹配,也就是匹配自己即可
对图黑白染色以决定是竖进横出还是横进竖出
向相邻格子匹配权为壁的代价
然后就变成了二分图最大权匹配

#include<stdio.h>#include<cstring> #include<queue>using namespace std;#define cint const int &#define poi(x,y) ((x-1)*m+y)#define Void inline void#define N 35#define M 2005int s[M],tot,S,T,Q[M*20],ans,pt[M],st[M],tm[M],ts,dis[M],n,m,c[N][N],r[N][N];bool w[N][N],vis[M];inline int rd() {    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}struct edge{int v,c,w,n;}e[M<<4];Void push(cint u,cint v,cint w){    e[++tot]=(edge){v,1,w,s[u]};s[u]=tot;    e[++tot]=(edge){u,0,-w,s[v]};s[v]=tot;}Void prepare(){    S=0,T=1;tot=1;ans=0;    #define clean(a) memset(a,0,sizeof(a))    clean(s);    clean(w);}inline bool BFS(){    tm[S]=++ts;    Q[1]=S;    for (int l=1,r=1;l<=r;l++)    {        vis[Q[l]]=0;        #define V e[i].v        for (int i=s[Q[l]];i;i=e[i].n) if (e[i].c && (tm[V]<ts || dis[V]<dis[Q[l]]+e[i].w))        {            if (tm[V]<ts) tm[V]=ts,vis[V]=0;            dis[V]=dis[st[V]=Q[l]]+e[pt[V]=i].w;            if (!vis[V]) vis[Q[++r]=V]=1;        }    }    if (tm[T]<ts) return 0;    for (int i=T;i!=S;i=st[i]) e[pt[i]].c=0,e[pt[i]^1].c=1;    ans+=dis[T];    return 1;}void solve(){    prepare();    n=rd(),m=rd();    for (int i=1;i<=n;i++) for (int j=1;j<m;j++) c[i][j]=rd();    for (int i=1;i<n;i++) for (int j=1;j<=m;j++) r[i][j]=rd();    for (int k=rd(),u,v;k--;u=rd(),v=rd(),w[u][v]=1);    for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)    {        int K=poi(i,j)<<1;        push(S,K|1,0);push(K,T,0);        if (!w[i][j]) push(K|1,K,0);    }    for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (i+j&1)    {        if (i<n) push(poi(i,j)<<1|1,poi(i+1,j)<<1,r[i][j]);        if (1<i) push(poi(i,j)<<1|1,poi(i-1,j)<<1,r[i-1][j]);    }    else    {        if (j<m) push(poi(i,j)<<1|1,poi(i,j+1)<<1,c[i][j]);        if (1<j) push(poi(i,j)<<1|1,poi(i,j-1)<<1,c[i][j-1]);    }    bool flag=1;    for (int i=1;i<=n*m;i++) if (!BFS()){flag=0;break;}    if (flag) printf("%d\n",ans);    else puts("Impossible");}main(){for (int T=rd(),i=1;i<=T;i++) printf("Case #%d: ",i),solve();}
0 0
原创粉丝点击