HDU1102 - Constructing Roads : http://acm.hdu.edu.cn/showproblem.php?pid=1102
题意 : 给你N个村庄,接下来是N行输入,第 i 行的第 j 个数字代表的是编号为 i 的村庄到编号为j的村庄的距离.例如 : 0 2 5. 表示村庄1到自己的距离为0,到村庄2的距离为2,到村庄3的距离是5,N行输入后又有Q行输入,每行两个整数x, y.表示x和y之间已经修好路了.问要将所有村庄连在一起,最少要修多长的公路.
思路 : 就是用最小生成树求解,,,,,,Prim + 优先队列 可节省时间.
代码 :
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 111;
const int Inf = 1<<30;
int Map[MAXN][MAXN],Vis[MAXN],Dist[MAXN],Ans;
int N,Q;
int x,y;
void Initial()
{
Ans = 0;
fill(Vis,Vis + MAXN,0);
fill(Dist,Dist + MAXN,Inf);
}
struct Node{
int v,len;//v是编号,len是v到目标集合的距离(将所有已经连在一起的村庄看成一个集合)
bool friend operator <(Node x,Node y)//用优先队列取出距离 已经连好的村庄 最近的村庄编号
{
return x.len > y.len;
}
};
void Prim()
{
priority_queue<Node>Edge;
Node Now;
Now.v = 1,Now.len = 0;//假设先从第一个村庄开始,从其他的编号开始也可以,但是 len一定是 0
Edge.push(Now);
while(!Edge.empty())
{
Now = Edge.top();
Edge.pop();
if(Vis[Now.v])continue;//已经在集合里,不再访问
Vis[Now.v] = 1;//否则标记为访问
Ans += Now.len;//同时把当前节点 v到目标集合的距离len加到答案里,优先队列里取出来的可以保证是最短的路
for(int i = 1;i <= N;i++)
{
if(!Vis[i] && Map[Now.v][i] < Dist[i])//满足此条件则可以加入队列
{
Node Next;
Next.v = i;
Next.len = Dist[i] = Map[Now.v][i];
Edge.push(Next);
}
}
}
printf("%d\n",Ans);
}
int main()
{
while(~scanf("%d",&N))
{
Initial();
for(int i = 1;i <= N;i++)
for(int j = 1;j <= N;j++)
scanf("%d",&Map[i][j]);
scanf("%d",&Q);
while(Q--)
{
scanf("%d%d",&x,&y);//x,y已经相连
Map[x][y] = Map[y][x] = 0;
}
Prim();
}
return 0;
}