关押罪犯

编程入门 行业动态 更新时间:2024-10-24 16:30:46

关押<a href=https://www.elefans.com/category/jswz/34/1763027.html style=罪犯"/>

关押罪犯

Description

  S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨 气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为 c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c的冲突事件。
每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S城Z市长那里。公务繁忙的Z市长只会去看列表中的第一个事件的影响力, 如果影响很坏,他就会考虑撤换警察局长。
  在详细考察了N名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那么,应如何分配罪犯,才能使Z市长看到的那个冲突事件的影响力最小?这个最小值是多少?

Input

  输入文件名为 prison.in。输入文件的每行中两个数之间用一个空格隔开。
  第一行为两个正整数N和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。
  接下来的M行每行为三个正整数 aj,bj,cj,表示aj号和bj号罪犯之间存在仇恨,其怨气值为cj。数据保证1≤aj

Output

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

Sample Input

4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884

Sample Output

3512

Hint

【样例说明】  

  罪犯之间的怨气值如下面左图所示,右图所示为罪犯的分配方法,市长看到的冲突事件 影响力是3512(由2号和3号罪犯引发)。其他任何分法都不会比这个分法更优。
  
  
【数据范围】
  对于30%的数据有N≤15。
  对于70%的数据有N≤2000,M≤50000。
  对于100%的数据有N≤20000,M≤100000。

Thinking

  这道题首先要想到并查集思路,这是解题的基础。首先考虑问题,如何安排罪犯才能做到最优决策?明显的可以看出,要尽量先安排仇恨值大的组合,将他们放到不同的监狱里。从大到小进行决策直到发现有某一组组合已经在同一个监狱里,那么输出他们的仇恨值就是最终的答案。现在问题又来了,第一组罪犯可以轻松地随意安排到两个监狱中,但是从第二组开始,两个人到底应该各自去哪一个监狱呢?

  这时要改变思路,既然维护罪犯在哪一个监狱不方便,那么我们干脆维护某两个罪犯不在一个监狱好了。考虑到并查集的本职工作是维护某两点在一个集合,不能很好地处理不在一个集合的情况,所以我们要曲线救国,通过保存某个点的“敌人”集合来代表和他不在一个监狱的罪犯,间接地实现维护某两点不在一个集合的情况。在加入关系的时候进行判断,如果某两点已经在一个集合,说明他们无论如何也安排不到不同的两个监狱了,输出仇恨值即可。

  至此算法框架基本浮现。

  (P.s 用并查集保存两点不在一个集合还可以使用对立点的方式,即给每一个实点都建立一个与之对立的虚点。当读取到A与B不在同一集合的信息时,将A与B’,B与A’分别连边,这样也可以表示A与B不在同一集合。判断过程与上面的方法相同,实现起来也很简单,大家不妨试一下)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn = 20005;
const int maxm = 100005;
struct Edge
{int u,v;int c;bool operator < (const Edge t) const{return c >= t.c;}
}edge[maxm];
int n,m;
int fa[maxn<<1];
int find(int x) { return x^fa[x]? fa[x]=find(fa[x]) : x; }
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n<<1;i++) fa[i]=i;for(int i=1;i<=m;i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].c);sort(edge+1,edge+m+1);for(int i=1;i<=m;i++){int x = find(edge[i].u) , y = find(edge[i].v);if(x==y){printf("%d",edge[i].c);return 0;}fa[x] = find(edge[i].v + n);fa[y] = find(edge[i].u + n);}printf("0");return 0;
}

二分图是这样一个图: 有两顶点集且图中每条边的的两个顶点分别位于两个顶点集中,每个顶点集中没有边相连接!
判断二分图的常见方法:开始对任意一未染色的顶点染色,之后判断其相邻的顶点中,若未染色则将其染上和相邻顶点不同的颜色, 若已经染色且颜色和相邻顶点的颜色相同则说明不是二分图,若颜色不同则继续判断,用深搜即可。因为是无向二分图的匹配,所以要除以2。
第二种做法使用二分图判定和二分答案。。
边从小到大排序之后二分是在哪条边发生最大冲突,那么当确定一条最大冲突的边的时候,需要对边权大于这条边的子图进行二分图判定,以判断是否还存在更大的冲突。。。
注意每次要从每个点尝试出发,因为可能不止一个连通分量。。
并且要在原图不存在冲突的时候输出0而不是最小边权。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn = 50005;
const int maxm = 100005;
struct Edge
{int to,next;
}edge[maxm<<1];
int head[maxn];
int maxedge;
inline void addedge(int u,int v)
{edge[++maxedge] = (Edge) { v,head[u] };head[u] = maxedge;edge[++maxedge] = (Edge) { u,head[v] };head[v] = maxedge;
}
struct Road
{int u,v;int c;bool operator < (const Road t) const{return c < t.c;}
}road[maxm];
int n,m;
int color[maxn];
bool bipartite(int u)
{for(int i=head[u];~i;i=edge[i].next){int v = edge[i].to;if(color[u] == color[v]) return false;if(!color[v]){color[v] = 3 - color[u];if(!bipartite(v)) return false;}}return true;
}
bool f(int lim)
{if(lim == m) return true;memset(color,0,sizeof(color));memset(head,-1,sizeof(head));maxedge = -1;for(int i=lim+1;i<=m;i++) addedge(road[i].u,road[i].v);for(int i=lim+1;i<=m;i++){if(!color[road[i].u]){color[road[i].u]=1;if(!bipartite(road[i].u)) return false;}if(!color[road[i].v]){color[road[i].v]=1;if(!bipartite(road[i].v)) return false;}}return true;
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=m;i++) scanf("%d%d%d",&road[i].u,&road[i].v,&road[i].c);sort(road+1,road+m+1);int l=1,r=m;while(l<r){int mid = (l+r)>>1;bool tmp = f(mid);if(tmp) r=mid;else l=mid+1;}if(l==1 && f(0)){printf("0");return 0;}printf("%d",road[l].c);return 0;
}

更多推荐

关押罪犯

本文发布于:2023-06-28 05:47:27,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/922679.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:罪犯

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!