考试的时候写的最大生成树,然后二分图染色,因为这样两个矛盾很大的罪犯不会被分在一个监狱里面。
然而最大生成树超时,80分。
正解为二分边权,将边权值大于mid的全部连边构图,判断是否为二分图,如果不是二分图,那么无解。
如果无解,则说明边权的限制条件太小了,因为连的边太多,不容易形成二分图;如果有解,则说明边权的限制条件太大,因为更少的边有利于形成二分图。
80分代码,最大生成树:
#include
#include
#include
#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
#include
#include
#include
#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