LOJ 2321 清华集训2017 无限之环 拆点+最小费用最大流

题面:中文题面,这里不占用篇幅

 

分析:

  看到题面,我就想弃疗……

  但是作为任务题单,还是抄了题解……

  大概就是将每个格子拆点,拆成五个点,上下左右的触点和一个负责连源汇点的点(以下简称本点)。

  这个这个本点要根据初始形态向相应的触点连接费用为0容量为1的边,再由旋转规则,使初始触点向相应的触点连接费用为旋转次数的边,然后相邻的格子触点相连?

  反正很乱就是了。如果再写一遍,我应该不会写罢……

代码:(这份代码在Luogu上不开O2会TLE十八组数据……开了才能过,在loj是可过的)

 1 #include<bits/stdc++.h>
 2 #define up(u) u+tn*sm
 3 #define ri(u) u+((tn+1)&3)*sm
 4 #define dn(u) u+((tn+2)&3)*sm
 5 #define le(u) u+((tn+3)&3)*sm
 6 #define md(u) u+(sm<<2)
 7 using namespace std;queue<int>q;
 8 const int N=20005,M=200005,inf=0x3f3f3f3f;
 9 struct node{int y,z,f,nxt;}e[M];
10 int mf=0,f[N],lst[N],ans=0;bool vis[N];
11 int sm,c=1,S=0,T,h[N],d[N],pre[N],n,m,k;
12 void add(int x,int y,int f,int z,int tp){
13     if(tp) swap(x,y);
14     e[++c]=(node){y,z,f,h[x]};h[x]=c;
15     e[++c]=(node){x,-z,0,h[y]};h[y]=c;
16 } bool spfa(){
17     for(int i=S;i<=T;i++) pre[i]=-1,
18     f[i]=inf,lst[i]=vis[i]=0,d[i]=inf;
19     q.push(S);d[S]=0;pre[S]=0;
20     while(q.size()){
21         int x=q.front();q.pop();vis[x]=0;
22         for(int i=h[x],y;i;i=e[i].nxt)
23         if(d[y=e[i].y]>d[x]+e[i].z&&e[i].f){
24             d[y]=d[x]+e[i].z;pre[y]=x;lst[y]=i;
25             f[y]=min(f[x],e[i].f);
26             if(!vis[y]) vis[y]=1,q.push(y);
27         }
28     } return (pre[T]!=-1);
29 } void solve(){
30     while(spfa()){
31         ans+=d[T]*f[T];int x=T;mf+=f[T];
32         while(x) e[lst[x]].f-=f[T],
33         e[lst[x]^1].f+=f[T],x=pre[x];
34     } return ;
35 } int main(){
36     k=1;int t,sp,tn,tf=0,mc=0;
37     scanf("%d%d",&n,&m);sm=n*m;T=sm*5+1;
38     for(int i=0;i<n;i++)
39     for(int j=0;j<m;j++,k++){
40         tn=0;t=(i+j)&1;
41         if(t) add(S,md(k),inf,0,0);
42         else add(md(k),T,inf,0,0);
43         if(i) add(dn(k-m),up(k),1,0,t);
44         if(j) add(ri(k-1),le(k),1,0,t);
45         scanf("%d",&sp);
46         if(sp&1) add(up(k),md(k),1,0,t),tf++;
47         if(sp&2) add(ri(k),md(k),1,0,t),tf++;
48         if(sp&4) add(dn(k),md(k),1,0,t),tf++;
49         if(sp&8) add(le(k),md(k),1,0,t),tf++;
50         switch(sp){
51             case 8:tn++;
52             case 4:tn++;
53             case 2:tn++;
54             case 1:
55                 add(ri(k),up(k),1,1,t);
56                 add(dn(k),up(k),1,2,t);
57                 add(le(k),up(k),1,1,t);break;
58             case 9:tn++;
59             case 12:tn++;
60             case 6:tn++;
61             case 3:
62                 add(dn(k),up(k),1,1,t);
63                 add(le(k),ri(k),1,1,t);break;
64             case 13:tn++;
65             case 14:tn++;
66             case 7:tn++;
67             case 11:
68                 add(dn(k),le(k),1,1,t);
69                 add(dn(k),up(k),1,2,t);
70                 add(dn(k),ri(k),1,1,t);break;
71         } 
72     } solve();
73     printf("%d",tf==mf<<1?ans:-1);return 0;
74 }
费用流

 


  

转载于:https://www.cnblogs.com/Alan-Luo/p/10242587.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值