题面太长了请各位自行品尝—>老C的方块
我们要解决掉所有使人弃疗的组合,还要保证花费最小,容易想到最小割(当然你要是想费用流的话,我们就没办法定义流量了)
我们来分析一下那些令人弃疗的组合,他们的规律:
首先是两个和特殊边直接相邻的方块(以下简称轴方块),加上两侧各任意一个边缘方块,组成了令人弃疗的组合。
所以我们有三种选择(准确地说其实只有两种,前两种本质一样):
1. 将和特殊边左侧的轴方块相连的所有边缘方块都破坏掉。
2. 将和特殊边右侧的轴方块相连的所有边缘方块都破坏掉。
3. 破坏掉任意一个轴方块。
我们还可以发现,特殊边两侧的部分相互独立。
所以我们可以应用染色技巧,怎么染色?当然是按照坐标(i+j)的奇偶性将图染成两种颜色。
之后从对于边缘方块及其轴方块,白点向黑点连边,流量为inf、
相邻的轴方块,黑点向白点连边,容量为较小的那个的代价、
之后S向白色边缘方块连边,容量为其代价,黑边缘方块向T连边,容量为其代价。
跑最小割。
细节很多,一着不慎满盘皆输!
代码:
1 #include<bits/stdc++.h> 2 #define ms(a,x) memset(a,x,sizeof(a)) 3 using namespace std;int tot=0; 4 const int N=100005,inf=0x3f3f3f3f; 5 int S,T,n,m,k,h[N],c=1,q[N],d[N]; 6 struct node{int y,z,nxt;}e[N*20]; 7 struct kuai{int x,y,w,id;}p[N]; 8 void add(int x,int y,int z){ 9 e[++c]=(node){y,z,h[x]};h[x]=c; 10 e[++c]=(node){x,0,h[y]};h[y]=c; 11 } bool bfs(){ 12 int f=1,t=0;ms(d,-1); 13 q[++t]=S;d[S]=0; 14 while(f<=t){ 15 int x=q[f++]; 16 for(int i=h[x],y;i;i=e[i].nxt) 17 if(d[y=e[i].y]==-1&&e[i].z) 18 d[y]=d[x]+1,q[++t]=y; 19 } return (d[T]!=-1); 20 } int dfs(int x,int f){ 21 if(x==T) return f;int w,tmp=0; 22 for(int i=h[x],y;i;i=e[i].nxt) 23 if(d[y=e[i].y]==d[x]+1&&e[i].z){ 24 w=dfs(y,min(e[i].z,f-tmp)); 25 if(!w) d[y]=-1;e[i].z-=w; 26 e[i^1].z+=w;tmp+=w; 27 if(tmp==f) return f; 28 } return tmp; 29 } void dinic(){ 30 while(bfs()) tot+=dfs(S,inf); 31 } bool cpx(kuai a,kuai b){ 32 return a.x!=b.x?a.x<b.x:a.y<b.y; 33 } bool cpy(kuai a,kuai b){ 34 return a.y!=b.y?a.y<b.y:a.x<b.x; 35 } int main(){ 36 scanf("%d%d%d",&n,&m,&k);S=0;T=k+1; 37 for(int i=1;i<=k;p[i].id=i,i++) 38 scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].w); 39 p[0].x=p[0].y=p[k+1].x=p[k+1].y=0; 40 sort(p+1,p+k+1,cpx); 41 for(int i=1;i<=k;i++) 42 if(p[i+1].x==p[i].x&&p[i+1].y==p[i].y+1){ 43 if(((p[i].x+p[i].y)&1)==0) 44 add(p[i].id,p[i+1].id,inf); 45 else add(p[i+1].id,p[i].id,inf); 46 } sort(p+1,p+k+1,cpy); 47 for(int i=1,val;i<=k;i++){ 48 if(p[i+1].x!=p[i].x+1||p[i+1].y!=p[i].y) 49 continue; 50 if(p[i].x%2&&p[i].y%2==((p[i].x-1)/2)%2) 51 continue; 52 if(p[i].x%2) val=min(p[i].w,p[i+1].w); 53 else val=inf;if(p[i].y%2) 54 add(p[i+1].id,p[i].id,val); 55 else add(p[i].id,p[i+1].id,val); 56 } for(int i=1;i<=k;i++) 57 if(((p[i].x-1)/2)%2==p[i].y%2){ 58 if((p[i].x+p[i].y)%2==0) 59 add(S,p[i].id,p[i].w); 60 else add(p[i].id,T,p[i].w); 61 } dinic(); 62 printf("%d\n",tot);return 0; 63 }
BZOJ 4823 Luogu P3756 老C的方块 染色+最小割
原文:https://www.cnblogs.com/Alan-Luo/p/10251533.html