soj3366: Watering Hole
http://acm.scu.edu.cn/soj/problem.action?id=3366
简介题意,农夫John要给他的几个牧场引水,到底是挖井还是挖管子呢,n个农场,每个地方挖井的钱,每段挖管子的钱已知,求最少花多少钱啦。
每个地方挖井?可以想象加一个点,这个点到各个点的距离是挖井的价格,那就相当于n+1个农场求最小生成树啦。就相当于把每个挖井的价格当做多一点,连线的权值。大不了画个四个点的图,再加一个点,瞬间就明白咯。
#include<cstdio>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
#define MAX 310
int map[MAX][MAX];
int dist[MAX];
bool visit[MAX];
void prim(int n)
{
memset(dist,INF,sizeof(dist));
memset(visit,0,sizeof(visit));
for(int i = 1;i <= n; i++)
if(map[1][i] != 0)
dist[i] = map[1][i];
visit[1] = 1;
int res = 0;
for(int i = 1;i <= n; i++)
{
int x;
int minx = INF;
for(int j = 1;j <= n; j++)
if(!visit[j]&&dist[j] < minx)
{
minx = dist[j];
x = j;
}
if(minx < INF)
{
visit[x] = 1;
res += minx;
for(int j = 1;j <= n; j++)
{
if(!visit[j]&&map[x][j]!=0&&map[x][j]<dist[j])
dist[j] = map[x][j];
}
}
}
printf("%d\n",res);
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(map,0,sizeof(map));
for(int i = 1;i <= n; i++)
{
int a;
scanf("%d",&a);
map[n+1][i] = map[i][n+1] = a;
}
for(int i = 1;i <= n; i++)
for(int j = 1;j <= n; j++)
scanf("%d",&map[i][j]);
n++;
prim(n);
}
return 0;
}
和昨天那道题几乎一模一样的,prim,主要在于想通把每个点的权值拉伸看成直线。