洛谷oj:P1525 [NOIP2010 提高组] 关押罪犯
#题目描述
#一看很明显是贪心算法 加排序 因为 这个中间最大值的那一对肯定是不会在一起的 从大到小来看 所有点对都尽量不要在一个监狱
#带权并查集 这个想不出来 只想到了并查集 来判段是不是在一个监狱 想不出怎么合并 (⊙ˍ⊙)
#知识点
并查集 贪心 排序 二分图(不了解)
#代码
第一次
10分 我想的是两个都不确定的情况就两种情况都试试 再来找小的那个值
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<stdio.h>
using namespace std;
int relat[20010];
int root[20010];
int sum[3];
int n,m,a,b,c,ans;
struct node
{
int x;
int y;
int z;
} Data[100020];
bool cmp(node a,node b)
{
return a.z < b.z;
}
void init()
{
for(int i=1; i<=n; i++)
{
root[i] = 0;
}
int i = m;
root[Data[i].x] = 1;
root[Data[i].y] = 2;
//cout << Data[i].x <<" "<< 1 <<" " <<Data[i].y <<" " << 2 <<endl;
for(int i=0; i<3; i++)
{
sum[i] = 0;
}
}
void dfs(int step)
{
if(step == 0)
{
ans = min(sum[1],sum[2]);
// cout << "有值了 " <<"ans = "<< ans <<endl;
return ;
}
int a = Data[step].x;
int b = Data[step].y;
// cout << a <<" 和 "<< b <<"有矛盾 值为 " <<Data[step].z <<endl;
// cout << root[a] << " " <<root[b] <<endl;
if(root[a] == root[b])//在同一个监狱 会有问题
{
if(root[a] == 0)//没出现过
{
//先将a放到 1 b放到2 再倒过来试试
root[a] = 1;
root[b] = 2;
dfs(step-1);
root[a] = 2;
root[b] = 1;
dfs(step-1);
}
else
{
sum[root[a]] = max(sum[root[a]],Data[step].z);
dfs(step-1);
}
}
else if(root[a] == 1) //在一号监狱
{
if(root[b] == 0)
{
root[b] = 2;
}
dfs(step-1);
}
else if(root[a] == 2) //在2号监狱
{
if(root[b] == 0)
{
root[b] = 1;
}
dfs(step-1);
}
else if(root[a] == 0) //没出现过
{
if(root[b] == 1)
{
root[a] = 2;
}
else if(root[b] == 2)
{
root[a] = 1;
}
dfs(step-1);
}
}
int main()
{
cin >> n >> m;
for(int i =1; i<= m ; i++)
{
cin >> a >> b >> c;
Data[i].x = a;
Data[i].y = b;
Data[i].z = c;
}
sort(Data+1,Data+1+m,cmp);
init();
// for(int i=1; i<=n; i++)
// {
// cout << i << " " <<root[i] <<endl;
// }
ans = 0x3f3f3f3f;
dfs(m-1);
cout << ans <<endl;
return 0;
}
第二次
后来改用了遍历 这个监狱 发现比第一种 递归还差 因为放在那个监狱当前不知道不代表之后不知道 有很大的局限性 后来看来看大佬的想法 (敌人的敌人对我不会是最差的那个) 这样的想法来合并 秒啊!!! (≧0≦)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<stdio.h>
using namespace std;
int relat[20010];
int root[20010];
int n,m,a,b,c,ans;
struct node
{
int x;
int y;
int z;
} Data[100020];
bool cmp(node a,node b)
{
return a.z > b.z;
}
void init()
{
for(int i=1; i<=n; i++)
{
root[i] = i;
}
memset(relat,0,sizeof(relat));
}
int Find(int a)
{
if(a == root[a])
return a;
else
{
root[a] = Find(root[a]);
return root[a];
}
}
int main()
{
cin >> n >> m;
for(int i=1;i<=m;i++)
{
cin >> Data[i].x >> Data[i].y >> Data[i].z ;
}
sort(Data+1,Data+1+m,cmp);
init();
// for(int i=1;i<=m;i++)
// {
// cout << Data[i].x <<"-" <<root[Data[i].x] <<" "<<Data[i].y <<"-" <<root[Data[i].y] <<endl;
// }
for(int i=1;i<=m+1;i++)//m+1时 有相同的根 所以会输出 0 妙啊!!
{
int a = Data[i].x;
int b = Data[i].y;
int ra = Find(a);
int rb = Find(b);
if(ra == rb)
{
cout << Data[i].z <<endl;//因为是降序排序 后面的不可能有这个大 这就是最大的了
break;
}else // 关系不好 是互相的 这个关系在没有解决 (这个合并的关系 敌人的敌人和我的关系没有对敌人那么不好 可以这么试着理解)
{
if(relat[a] == 0)//a 没有关系不好的
{
relat[a] = b;//当前这个就是同a关系不好的
}
else//a 有关系不好的
{
c = relat[a];//b 和这个c 在一个监狱 c是a的敌人
int rc = Find(c);
if(rc != rb)
{
root[rc] = rb;
}
}
if(relat[b] == 0)//b 没有关系不好的
{
relat[b] = a;//当前这个就是同b关系不好的
}else//b 有关系不好的
{
c = relat[b];//a 和这个c 在一个监狱 c是b的敌人
int rc = Find(c);
if(rc != ra)
{
root[rc] = ra;
}
}
}
}
return 0;
}
#总结
这个想法要多思考多理解 这是没错的 常话还是有道理的 ^ _ ^