其他分享
首页 > 其他分享> > P1525 [NOIP2010 提高组] 关押罪犯

P1525 [NOIP2010 提高组] 关押罪犯

作者:互联网

原题链接

考察:二分+二分图判定 or 带权并查集+贪心

思路一:

           二分+二分图判定.由题目可知我们要求最大矛盾的最小值.最小值可以通过二分枚举,那么关键是如何check.首先容易想到>最小值的两个人一定不能在同一集合.需要将它们分别放在不同的监狱.那么问题来了:这样存放可能会导致某些破坏最小值合法性的两个点因为前面的放置在同一监狱里.这样就有点像二分图染色.不同颜色代表不同监狱.通过判断二分图的合法性来判断最小值的合法性.

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N = 100010,M = 20000;
 6 int n,m,h[M],idx,color[M];
 7 struct Hate{
 8     int a,b,w;
 9 }hate[N];
10 struct Road{
11     int to,ne,w;  
12 }road[N<<1];
13 void add(int a,int b,int w)
14 {
15     road[idx].w = w,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
16 }
17 bool dfs(int u,int c,int maxn)
18 {
19     color[u] = c;
20     for(int i=h[u];i!=-1;i=road[i].ne)
21     {
22         int v = road[i].to;
23         if(road[i].w<=maxn) continue;
24         if(!color[v])
25         {
26             if(!dfs(v,3-c,maxn))return false;
27         }else if(color[v]==c) return false;
28     }
29     return 1;
30 }
31 bool check(int maxn)
32 {
33     memset(color,0,sizeof color);
34     for(int i=1;i<=n;i++)
35         if(!color[i])
36             if(!dfs(i,1,maxn)) return false;
37     return true;
38 }
39 int main()
40 {
41     scanf("%d%d",&n,&m);
42     memset(h,-1,sizeof h);
43     for(int i=1;i<=m;i++)
44     {
45         scanf("%d%d%d",&hate[i].a,&hate[i].b,&hate[i].w);
46         add(hate[i].a,hate[i].b,hate[i].w),add(hate[i].b,hate[i].a,hate[i].w);
47     }
48     int l = 0,r = 1e9+10;
49     while(l<r)
50     {
51         int mid = l+r>>1;
52         if(check(mid)) r = mid;
53         else l = mid+1;
54     }
55     printf("%d\n",r);
56     return 0;
57 }
二分图

思路二:

          并查集+贪心.受食物链启发,我们可以将与根节点距离为0的点代表与根节点同一监狱.距离为1代表不同监狱.通过并查集维护距离,来判定最小值是否合法.但这里不需要枚举最小值.我们对仇恨值从大到小排序,如果可以避免在同一监狱,就将它们放在不同监狱.如果不能,此仇恨值就是ans,后面就可以随便放了,反正仇恨值不会超过ans

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N = 100010,M = 20000;
 6 struct Hate{
 7     int l,r,w;
 8     bool operator<(Hate x){
 9         return this->w>x.w;
10     }
11 }hate[N];
12 int n,m,p[M],d[M];
13 int findf(int x)
14 {
15     if(p[x]!=x)
16     {
17         int px = findf(p[x]);
18         d[x] +=d[p[x]];
19         p[x] = px;
20     }
21     return p[x];
22 }
23 int main()
24 {
25     scanf("%d%d",&n,&m);
26     for(int i=1;i<=m;i++) scanf("%d%d%d",&hate[i].l,&hate[i].r,&hate[i].w);
27     sort(hate+1,hate+m+1);
28     for(int i=1;i<=n;i++) p[i] = i;
29     for(int i=1;i<=m;i++)
30     {
31         int x = hate[i].l,y = hate[i].r;
32         int px = findf(x),py = findf(y);
33         if(px!=py)
34         {
35             d[px] = d[y]-d[x]-1;
36             p[px] = py;
37         }else if((d[y]-d[x])%2==0) {printf("%d\n",hate[i].w);return 0;}
38     }
39     printf("%d\n",0);
40     return 0;
41 }
带权并查集

 

标签:P1525,二分,查集,关押,int,NOIP2010,最小值,include,监狱
来源: https://www.cnblogs.com/newblg/p/14646320.html