题意:国王的领土被分割成n个地方,国王想到达他领土的每一个地方,但是现在一些有一些城墙的隔绝两个地方,拆掉城墙需要耗费 一些财力物力,国王想拆最小的城墙数,花费最小的人力物力。给出的数据 ,开始给出的n个坐标值,(这个是唬人的,一点用都没有),而后给出 u v w表示一个城墙连接的两个地方和拆掉需要耗费的代价了。
思路:这个题,当时翻译出了,我直接想到最是最小生成树,共有 n(n+1)/2 条路 ,其中给出的路是需要耗费代价的,没给出是不需要耗费代价的,这样建立最小生成树,但是数据太大,矩阵不能存储标记,而且排序和两层for会超时,这个方案就被舍弃了,比赛时,出现一点意外,我们就没继续深入解这个题。 上网搜题解:看到最大生成树,当时豁然开朗,n个地方最多n-1条路 ,再多加一条路,就会成圈。因此我们可以对立思考,保留下最大的生成树,这些就是不必要拆除的 ,余下的都需要拆除。还有一种可能,给出的数据够不成 最大的生成树,但是会构成圈 ,那么我们在建立最大生成树的时候,就会摒除构成圈的边(我在后来写这个题时就掉这个坑中,爬了好久,很菜),至于够不成最大的生成树,这个不用管,只需要它们够不成圈即可。
总结:可能是题刷的不够多,题型见的也不多吧,对于这种稍微变形的题,当时可能就做不出来,ACM比赛,可能不止比你的算法,更考你的发散思维吧。各种各样的题型,千奇百怪的解法,可以引导人发散的思维。
AC代码:
#include <stdio.h>
#include <algorithm>
using namespace std;
#include <string.h>
#include <iostream>
int n,m;
int father[1100000];
struct node
{
int x;
int y;
int k;
}Q[1100000];
int find(int x)
{
if(father[x]==x)
return x;
return father[x]=find(father[x]);
}
bool cmp(node a,node b)
{
return a.k>b.k;
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
int a,b;
for(int i=1;i<=n;i++)
{
scanf("%d %d",&a,&b);
father[i]=i;
}
int cont=0,sum=0,st=0;
for(int i=0;i<m;i++)
{
scanf("%d %d %d",&Q[i].x,&Q[i].y,&Q[i].k);
cont+=Q[i].k;
}
sort(Q,Q+m,cmp);
for(int i=0;i<m;i++)
{
int tx=find(Q[i].x);
int ty=find(Q[i].y);
if(tx!=ty)
{
sum+=Q[i].k;
st++;
father[tx]=ty;
if(st==n-1)
break;
}
}
printf("%d %d\n",m-st,cont-sum);
}
return 0;
}