【9008】香甜的黄油

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

农夫John发现做出全威斯康辛州最甜的黄油的方法:糖。把糖放在一片牧场上,他知道N(1<=N<=500)只奶牛会过来舔它,这样就
能做出能卖好价钱的超甜黄油。当然,他将付出额外的费用在奶牛上。
农夫John很狡猾。像以前的Pavlov,他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。他打算将糖放在那里然后下午发出铃声,以至他可以在晚上挤奶。
农夫John知道每只奶牛都在各自喜欢的牧场(一个牧场不一定只有一头牛)。给出各头牛在的牧场和牧场间的路线,找出使所有牛
到达的路程和最短的牧场(他将把糖放在那)

【输入格式】

第一行: 三个数:奶牛数N,牧场数(2<=P<=800),牧场间道路数C(1<=C<=1450)
第二行到第N+1行: 1到N头奶牛所在的牧场号
第N+2行到第N+C+1行: 每行有三个数:相连的牧场A、B,两牧场间距离D(1<=D<=255),当然,连接是双向的

【输出格式】

一行 输出奶牛必须行走的最小的距离和

Sample Input

3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5
{样例图形
          P2  
P1 @--1--@ C1
         |
         | 
       5  7  3
         |   
         |     C3
       C2 @--5--@
          P3    P4
}

【题解】

対每个点都进行一次spfa。牛从各个牛场到某个牛场的过程,可以看成是多头牛从一个牛场分别走回各自的牛场。所走过的距离是一样的。

进行多次spfa,然后记录下每个牛场的牛的数目。在每个牛场进行的spfa获得的dis数组用于累加所有牛走过的总距离。枚举每个牛场,获得这个总距离的最小值即可。最后输出。

初值设置成-1, 便于进行判断这个牛场是否为无穷大。

【代码】

#include <cstdio>
#include <cstring>

int n,p,c,a[900][900],w[900][900],num[900],dis[900],team[20000],mins = -1;
bool exsit[1000];

void input_data()
{
	scanf("%d%d%d",&n,&p,&c); //n是牛的总数。p是牛场的数目。C是道路数 
	for (int i = 1;i <= n;i++)
		{
			int x;
			scanf("%d",&x);
			num[x]++;
		}
	for (int i = 1;i <= c;i++) //输入n条路 
		{
			int x0,y0,z0;
			scanf("%d%d%d",&x0,&y0,&z0); //因为是无向图,所以要两边的出度都增加都记录。	
			a[x0][0]++;
			a[x0][a[x0][0]] = y0;
			w[x0][y0] = z0;
			a[y0][0]++;
			a[y0][a[y0][0]] = x0;
			w[y0][x0] = z0;
		}
}

void nspfa()
{	
	for (int i =1 ;i <= p;i++) //枚举放奶糖的牛场编号。 
		{
			memset(exsit,false,sizeof(exsit)); //一开始所有的牛场都不在队列中 
			for (int j = 1;j <= p;j++)
				dis[j] = -1;
			dis[i] = 0; //假设从第i号牛场进行spfa 
			exsit[i] = true;
			team[1] = i; //把i加入队列 
			int head = 0,tail = 1;
			while (head != tail)
				{	
					head++;
					head = ((head - 1) % 19000) + 1; //用循环队列 
					int f = team[head];
					exsit[f] = false; 
					for (int j = 1;j <= a[f][0];j++)
						{
							int t = a[f][j]; //f是起点 t是终点 
							if (dis[t] == -1 || dis[t] > dis[f] + w[f][t]) //如果能更新更优解则更新 
								{ //-1代表正无穷。 
									dis[t] = dis[f] + w[f][t];
									if (!exsit[t]) //如果终点不在队列中 则加入队列。 
										{
											exsit[t] = true;
											tail++;
											tail = ((tail-1) % 19000) + 1;
											team[tail] = t;	
										}
								}
						}
				}
			int sum = 0;
			for (int j = 1;j <= p;j++) //直接累加,不用判断是不是起点(起点为0) 
				sum+= num[j]*dis[j];
			if (mins == -1)
				mins = sum;
					else
						if (sum < mins)
							mins = sum;
		}
}

void output_ans()
{
	printf("%d
",mins);	
}

int main()
{
	//freopen("F:\rush.txt","r",stdin);
	input_data();
	nspfa();
	output_ans();
	return 0;	
}


原文地址:https://www.cnblogs.com/AWCXV/p/7632409.html