标签:图论
考试的时候写的最大生成树,然后二分图染色,因为这样两个矛盾很大的罪犯不会被分在一个监狱里面。
然而最大生成树超时,80分。
正解为二分边权,将边权值大于mid的全部连边构图,判断是否为二分图,如果不是二分图,那么无解。
如果无解,则说明边权的限制条件太小了,因为连的边太多,不容易形成二分图;如果有解,则说明边权的限制条件太大,因为更少的边有利于形成二分图。
80分代码,最大生成树:
#include<cstdio> #include<cstring> #include<algorithm> #define MAXN 20005 using namespace std; struct T { int u; int v; int w; bool f; }a[100005]; bool cmp(T x,T y) { return x.w > y.w; } int fa[MAXN]; int find(int x) { if(fa[x] == x) return fa[x]; else return fa[x] = find(fa[x]); } struct E { int v; int w; int next; bool used; }edge[100005]; int cnt,head[MAXN]; void add_edge(int u,int v,int w,bool flag) { edge[cnt].v = v; edge[cnt].w = w; edge[cnt].used = flag; edge[cnt].next = head[u]; head[u] = cnt++; } int n,m; int belong[MAXN]; int ans; bool vis[MAXN]; void dfs(int u,int fa)//二分图染色+选边权最大值 { belong[u] = (belong[fa]+1)%2; vis[u] = 1; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if(edge[i].used == 0&&belong[v] != -1&&belong[v] == belong[u]) { ans = max(ans,edge[i].w); } else if(edge[i].used == 1&&!vis[v]) { dfs(v,u); } } } int main() { //freopen("prison.in","r",stdin); //freopen("prison.out","w",stdout); memset(head,-1,sizeof head); scanf("%d%d",&n,&m); for(int i = 0; i < m; i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); a[i].u = x; a[i].v = y; a[i].w = z; a[i].f = 0; } sort(a,a+m,cmp); for(int i = 0; i <= n; i++) fa[i] = i; for(int i = 0; i < m; i++)//最大生成树 { int fx = find(a[i].u); int fy = find(a[i].v); if(fx != fy) { a[i].f = 1; fa[fx] = fy; add_edge(a[i].u,a[i].v,a[i].w,1); add_edge(a[i].v,a[i].u,a[i].w,1); } } for(int i = 0; i < m; i++)//没有使用的边,如果两个点的连边是这种边而且两个点被染的颜色相同,那么他们是属于一个监狱的,因此答案为符合上述条件的最大边权 { if(a[i].f == 0) { add_edge(a[i].u,a[i].v,a[i].w,0); add_edge(a[i].v,a[i].u,a[i].w,0); } } memset(belong,-1,sizeof belong); for(int i = 1; i <= n; i++) { if(belong[i] == -1) dfs(i,0); } printf("%d\n",ans); return 0; }
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define MAXN 20005 using namespace std; struct T { int v; int next; }edge[100005]; int head[MAXN],cnt; void add_edge(int u,int v) { edge[cnt].v = v; edge[cnt].next = head[u]; head[u] = cnt++; } struct E { int u; int v; int w; bool operator < (const E &x) const { return w > x.w; } }a[100005]; int n,m; int color[MAXN]; bool flag; bool dfs(int u)//二分图染色 { for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if(color[v] == color[u]) { return false; } else if(color[v] == -1) { color[v] = (color[u]+1)%2; if(dfs(v) == false) return false; } } return true; } bool check(int limit) { cnt = 0; memset(head,-1,sizeof head); memset(color,-1,sizeof color); memset(edge,0,sizeof edge); for(int i = 0; i < m; i++)//把边权大于限制条件的全部连边 { if(a[i].w <= limit) break; add_edge(a[i].u,a[i].v); add_edge(a[i].v,a[i].u); } for(int i = 1; i <= n; i++) { if(color[i] == -1) { color[i] = 0; if(dfs(i) == false) return false;//染色不成功,limit太小 } } return true; } int main() { scanf("%d%d",&n,&m); int l,r,mid; for(int i = 0; i < m; i++) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w),r = max(r,a[i].w); sort(a,a+m);//这里是否排序对结果没有太大的影响 l = -1;//注意边界条件 while(l+1<r) { mid = (l+r)/2; if(check(mid)) r = mid; else l = mid; } printf("%d\n",r); }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:图论
原文地址:http://blog.csdn.net/cqbzwja/article/details/47705863