洛谷——P1525 关押罪犯


https://www.luogu.org/problem/show?pid=1525

题目描述

S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。

那么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

输入输出格式

输入格式:

输入文件的每行中两个数之间用一个空格隔开。第一行为两个正整数N 和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。接下来的M 行每行为三个正整数aj,bj,cj,表示aj 号和bj 号罪犯之间存在仇恨,其怨气值为cj。数据保证1<aj=<=bj<=N ,0 < cj≤ 1,000,000,000,且每对罪犯组合只出现一次。

输出格式:

共1 行,为Z 市长看到的那个冲突事件的影响力。如果本年内监狱中未发生任何冲突事件,请输出0。

输入输出样例

输入样例#1:
4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884
输出样例#1:
3512

说明

【输入输出样例说明】罪犯之间的怨气值如下面左图所示,右图所示为罪犯的分配方法,市长看到的冲突事件影响力是3512(由2 号和3 号罪犯引发)。其他任何分法都不会比这个分法更优。

【数据范围】对于30%的数据有N≤ 15。对于70%的数据有N≤ 2000,M≤ 50000。对于100%的数据有N≤ 20000,M≤ 100000。

思路一:二分答案+二分图染色<<——最大值最小

得到一个怒气值后,给二分图染色;

如果当前有两人的怒气值<=二分出的怒气值,则给两人染色(放到两个监狱)

反之 ,两人怒气值>二分出的怒气值并且在同一个监狱 ,就说明 当前二分结果不合法,继续二分~~

  1 #include <algorithm>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 
  6 using namespace std;
  7 
  8 const int N(20000+15);
  9 const int M(100000+5);
 10 int n,m,u,v,w;
 11 
 12 struct E
 13 {
 14     int u,v,w;
 15 }e[M];
 16 bool cmp(E a,E b)
 17 {
 18     return a.w<b.w;
 19 }
 20 
 21 int head[N],sumedge;
 22 struct Edge
 23 {
 24     int u,v,next,rencor;
 25     Edge(int u=0,int v=0,int next=0,int rencor=0):
 26         u(u),v(v),next(next),rencor(rencor){}
 27 }edge[M<<1];
 28 void ins(int u,int v,int rencor)
 29 {
 30     edge[++sumedge]=Edge(u,v,head[u],rencor);
 31     head[u]=sumedge;
 32 }
 33 
 34 int col[N],flag;
 35 bool paint(int now,int rencor)
 36 {
 37     queue<int>que;
 38     que.push(now);
 39     col[now]=0;
 40     for(;!que.empty();)
 41     {
 42         int fro=que.front();que.pop();
 43         for(int i=head[fro];i;i=edge[i].next)
 44         {
 45             if(edge[i].rencor<=rencor) continue;
 46             v=edge[i].v;
 47             if(col[v]!=-1)
 48             {
 49                 if(col[v]==col[fro])
 50                 {
 51                     flag=0;
 52                     return false;
 53                 }
 54             }
 55             else
 56             {
 57                 col[v]=col[fro]^1;
 58                 que.push(v);
 59             }
 60         }
 61     }
 62     flag=1;
 63     return true;
 64 }
 65 
 66 int l,r,mid,ans;
 67 bool check(int x)
 68 {
 69     flag=0;
 70     memset(col,-1,sizeof(col));
 71     for(u=1;u<=n;u++)
 72         if(col[u]==-1)
 73         {
 74             paint(u,x);
 75             if(!flag)  //只要是有一个人无法合理分配,就不合法 
 76                 return false;
 77             flag=0;
 78         }
 79     return true;
 80 }
 81 
 82 int main()
 83 {
 84     scanf("%d%d",&n,&m);
 85     for(int i=1;i<=m;i++)
 86     {
 87         scanf("%d%d%d",&u,&v,&w);
 88         ins(u,v,w); ins(v,u,w);
 89         e[i].u=u;e[i].v=v;e[i].w=w;
 90     }
 91     sort(e+1,e+m+1,cmp);
 92     l=0;r=m;
 93     for(;l<=r;)
 94     {
 95         mid=l+r>>1;
 96         if(check(e[mid].w))
 97         {
 98             ans=e[mid].w;
 99             r=mid-1;
100         }
101         else l=mid+1;
102     }
103     printf("%d\n",ans);
104     return 0;
105 }
二分答案+染色判断

思路二:并查集染色法

只有两个监狱

用fa[1——n ]表示不能与i在一起的点(敌人的组织),fa[n+1——2*n]表示能与i在一起的点(朋友的组织)

敌人的敌人就是朋友,

 1 #include <algorithm>
 2 #include <cstdio>
 3 
 4 using namespace std;
 5 
 6 const int N(20000+15);
 7 const int M(100000+5);
 8 int n,m,fa[N<<1];
 9 
10 struct Edge
11 {
12     int u,v,w;
13 }edge[M];
14 bool cmp(Edge a,Edge b)
15 {
16     return a.w>b.w;
17 }
18 
19 int find(int x)
20 {
21     return fa[x]==x?x:fa[x]=find(fa[x]);
22 }
23 
24 int main()
25 {
26     scanf("%d%d",&n,&m);
27     for(int i=1;i<=n<<1;i++) fa[i]=i;
28     for(int i=1;i<=m;i++)
29         scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
30     sort(edge+1,edge+m+1,cmp);
31     for(int i=1;i<=m;i++)
32     {
33         int fx=find(edge[i].u),fy=find(edge[i].v);
34         if(fx==fy)
35         {
36             printf("%d\n",edge[i].w);
37             return 0;
38         }
39         fa[fx]=find(edge[i].v+n);
40         fa[fy]=find(edge[i].u+n);
41     }
42     puts("0");
43     return 0;
44 }
并查集

优质内容筛选与推荐>>
1、JSTL String时间转成 date
2、批量传递ID数组字符串到后台的处理
3、SharePoint SPServices —— 读取sharepoint lsit 数据的强大jquery 库
4、表单验证-阻止事件发生的应用
5、断点续传


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn