题目传送门FZU-2233点击进行传送=—+->
题目理解
给一个 N*N 的矩阵表示两种药混合后的效果值(i,j)的值就是 i 药物与 j 药物混合的效果值。
当把这n个物品分成两部分后,每部分内部材料不会相互影响,但是不同部分的材料之间会相互影响。
问如何分割使得两部分材料相互之间的最小影响值最大
思路
因为材料内部不会相互影响,所以只要进可能的让混合之后效果值小的两种材料在同一部分,那么最终的得到的药物效果值就一定是尽可能大的。
具体解决
用一个结构体来保存两种药物组合和效果值,并进行排序。
然后用并查集来保存药物之间的关系,按照效果值从小到大的顺序将不同的药物连成集合。
如果集合只有两个了,那么显然下一个使两个集合连成一体的药物关系就是我们要找的最终结果。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Node
{
int x,y,val;
bool friend operator < (Node n1, Node n2)
{
return n1.val < n2.val;
}
}a[640005];
int n;
int pre[805];
void init()
{
for (int i = 0; i <= n; i++)
pre[i] = i;
memset(a,0,sizeof a);
return;
}
int Find(int x)
{
if (x!=pre[x])
pre[x] = Find(pre[x]);
return pre[x];
}
int cal()
{
int ans = 0;
for (int i = 0 ; i < n; i++)
if (pre[i]==i)
ans++;
return ans;
}
int main()
{
while(cin >> n)
{
init();
int tmp;
int cnt = 0;
for (int i = 0 ; i < n; i++)
{
for (int j = 0 ; j < n; j++)
{
scanf("%d",&tmp);
if (i<j)
{
a[cnt].x = i;
a[cnt].y = j;
a[cnt++].val = tmp;
}
}
}
sort(a,a+cnt);
for (int i = 0 ; i < cnt ; i++)
{
int x = Find(a[i].x);
int y = Find(a[i].y);
if(x==y) continue;
if (cal()==2)
{
printf("%d\n",a[i].val);
break;
}
else
{
pre[x] = y;
}
}
}
return 0;
}
其实在计算并查集集合的数量的时候有两种思路
- 每次全部过一遍,计算集合数量
即:
for(i=0;i<n;i++)
if(father[i]==i)
count++;
先保存一下集合的总数,在每次将两个集合合并的时候把总数减一
for(i=0; i<k; i++)
{
int x = Find(a[i].x);
int y = Find(a[i].y);
if(x==y) continue;
if(x!=y && cnt>2)
{
f[x] = y;
cnt--;
}
else
ans = min(ans, a[i].cost);
if(ans!=INF) break;
}
好弱啊,交了20遍 (逃~