BZOJ 4823 Luogu P3756 老C的方块 染色+最小割

题面太长了请各位自行品尝—>老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 }
染色最小割

 

posted @ 2019-01-10 18:00  杜宇一声  阅读(185)  评论(0编辑  收藏  举报