码迷,mamicode.com
首页 > 其他好文 > 详细

小行星

时间:2018-03-13 22:48:07      阅读:232      评论:0      收藏:0      [点我收藏+]

标签:AC   没有   时间   数据   bad   region   相等   +=   img   

题目描述

星云中有n颗行星,每颗行星的位置是(x,y,z)。每次可以消除一个面(即x,y或z坐标相等)的行星,但是由于时间有限,求消除这些行星的最少次数。

输入输出格式

输入格式:

 

第1行为小行星个数n,第2行至第n+1行为xi, yi, zi,描述第i个小行星所在的位置。

 

输出格式:

 

共1行,为消除所有行星的最少次数。

 

输入输出样例

输入样例#1: 
3
1 2 3
2 3 1
1 3 2
输出样例#1: 
2

说明

1≤n≤50000

1≤x,y,z≤500

解:

看到数据范围,以及“消除”、“最少次数”的字样,就知道与最小割有关。问题在于怎么割呢?

要消除一颗小行星,可以从三个面来消除。xx 面,yy 面和 zz 面。不难想到,将这三个面上的每一个坐标建两个点——入点和出点。由入点向出点连一条容量为 11 的边。当入点和出点之间的这条边被割掉时,就说明是在这个面的这一个点消除了一次。

我们想要消除所有的小行星,就说明每一颗小行星在 xx 面,yy 面或 zz 面这三个面中,至少有一个面把它消除了。也就是说,不存在一条连通 x-y-zx?y?z 的路径,这就是割了。

于是我们对于每一颗小行星,从 xx 面的出点向 yy 面的入点连一条容量为 INFINF 的边(仅为保证点之间的连通性),从 yy 面的出点向 zz 面的入点连容量为 INFINF 的边。再从超级源向每个 xx 面的入点连容量为 INFINF 的边,从每个 zz 面的出点向超级汇连容量为 INFINF 的边。

建出来的图大致如下(样例):

技术分享图片

 

根据上面的分析,显然地,就是求 s-ts?t 最小割,这样就能保证每颗小行星都被消在某个面上。

但是……图好乱……

不难发现,这张图是可以简化的。注意到从超级源 SS 向每一个 xx 连出的边,下一条边都是从 xx 的入点向 xx 的出点连的一条容量为 11 的边。根据 Total Flow 一题可知,这两条边就类似于串联的关系,是可以合并的。

于是我们简化了这张图,改为直接从超级源 SS 向每个 xx (入点就可以不要了,于是就没有出入点之分了)连一条权值为 11 的边。从 zz 面的边到终点同理,也可以简化。

简化后的图大致如下:

 技术分享图片

 

这样只要拆 yy 面的点就好了。是不是清爽多了?

最后求解该图的最小割即可。

技术分享图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<string>
 7 #include<queue>
 8 #include<map>
 9 #define ll long long
10 #define DB double
11 #define inf 2147480000
12 using namespace std;
13 const int N=1e6+90;
14 struct node{
15     int u,v,fl,ne;
16 }e[N];
17 int h[N],tot;
18 void add1(int u,int v,int fl)
19 {
20     tot++;e[tot]=(node){u,v,fl,h[u]};h[u]=tot;
21 }
22 void add(int u,int v,int fl)
23 {
24     add1(u,v,fl);add1(v,u,0);
25 }
26 int q[N],d[N],hh,tt,S,T;
27 bool bfs()
28 {
29     for(int i=S;i<=T;++i) d[i]=0;
30     d[S]=1;hh=1;tt=0;q[++tt]=S;
31     while(hh<=tt)
32     {
33         int ff=q[hh];hh++;
34         for(int i=h[ff];i;i=e[i].ne)
35         {
36             int rr=e[i].v;
37             if(!d[rr] && e[i].fl)
38              d[rr]=d[ff]+1,q[++tt]=rr;
39         }
40     }
41     return d[T];
42 }
43 int dfs(int u,int fl)
44 {
45     if(u==T || !fl) return fl;
46     int get=0,f;
47     for(int i=h[u];i;i=e[i].ne)
48     {
49         int rr=e[i].v;
50         if(d[rr]==d[u]+1 && e[i].fl)
51         {
52             f=dfs(rr,min(fl,e[i].fl));
53             if(f==0) continue;
54             e[i].fl-=f;e[i^1].fl+=f;
55             get+=f;fl-=f;
56             if(fl==0) break;
57         }
58     }
59     if(get==0) d[u]=0;
60     return get;
61 }
62 int Flow()
63 {
64     int ans=0;
65     while(bfs()) ans+=dfs(S,inf);
66     return ans;
67 }
68 int n;
69 int main()
70 {
71     scanf("%d",&n);
72     S=0;T=500*4+1;tot=1;
73     for(int i=1;i<=500;++i)
74     {
75         add(S,i,1);
76         add(i+500*3,T,1);
77     }
78     for(int o=1,x,y,z;o<=n;++o)
79     {
80         scanf("%d%d%d",&x,&y,&z);
81         add(x,y+500,inf);
82         add(y+500,y+500*2,1);
83         add(y+500*2,z+500*3,inf);
84     }
85     cout<<Flow();
86     return 0;
87 }
View Code
 

小行星

标签:AC   没有   时间   数据   bad   region   相等   +=   img   

原文地址:https://www.cnblogs.com/adelalove/p/8562970.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!