「CODEVS2038」香甜的黄油
题目描述
农夫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),当然,连接是双向的。
输出
一行输出奶牛必须行走的最小的距离和。
样例输入
3 4 5 2 3 4 1 2 1 1 3 5 2 3 7 2 4 3 3 4 5
样例输出
8
题解
第一种做法SPFA,写起来最快,队列没有判重,内存4016,耗时912
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include<iostream> #include<cstring> using namespace std; int n,p,c; int dis[801],a[801][801],b[501],dl[801],t,w,tot,mn=0x7fffffff; void spfa(int x) {     memset(dis,127,sizeof(dis));     int t=0,w=1;     dl[t]=x;     dis[x]=0;     while(t<w)     {               for(int i=1;i<=p;i++)               {                  if(a[dl[t]][i]+dis[dl[t]]<dis[i])                  {                                                     dl[w]=i;                                                     dis[i]=a[dl[t]][i]+dis[dl[t]];                                                     w++;                                                     }               }               t++;     }     tot=0;     for(int i=1;i<=n;i++)     {             tot+=dis[b[i]];             } } int main() {     memset(a,127,sizeof(a));     cin>>n>>p>>c;     int x,y,z;     for(int i=1;i<=n;i++)        cin>>b[i];     for(int i=1;i<=c;i++)        {        cin>>x>>y>>z;        a[x][y]=a[y][x]=z;        }     for(int i=1;i<=p;i++)     {     spfa(i);     if(tot<mn)mn=tot; }     cout<<mn;     //system("pause");     return 0; } | 
加入队列判重和循环队列 740ms
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #include<iostream> #include<cstring> using namespace std; int n,p,c; int dis[801],a[801][801],b[501],dl[805],t,w,tot,mn=0x7fffffff; void spfa(int x) {     memset(dis,127,sizeof(dis));     int t=0,w=1;     bool pd[801]={0};     dl[t]=x;     pd[x]=1;     dis[x]=0;     while(t!=w)     {               for(int i=1;i<=p;i++)               {                  if(a[dl[t]][i]+dis[dl[t]]<dis[i])                  {                                                     dis[i]=a[dl[t]][i]+dis[dl[t]];                                                     if(!pd[i])                                                     {                                                     dl[w]=i;                                                     w++;                                                     w=(w-1)%801+1;                                                     pd[i]=1;                                                     }                  }               }               pd[dl[t]]=0;               t++;               t=(t-1)%801+1;     }     tot=0;     for(int i=1;i<=n;i++)     {             tot+=dis[b[i]];             } } int main() {     memset(a,127,sizeof(a));     cin>>n>>p>>c;     int x,y,z;     for(int i=1;i<=n;i++)        cin>>b[i];     for(int i=1;i<=c;i++)        {        cin>>x>>y>>z;        a[x][y]=a[y][x]=z;        }     for(int i=1;i<=p;i++)     {     spfa(i);     if(tot<mn)mn=tot; }     cout<<mn;     return 0; } | 
试试dijkstra+堆优化 88ms
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | #include<iostream> #include<cstring> using namespace std; struct data{ 	int v,w,next; }e[3001]; int g[801]; int n,p,c,ne=0,size; int cow[501]; int dis[801]; int num[801],pos[801]; void insert(int u,int v,int c) { 	ne++; 	e[ne].w=c;e[ne].v=v;e[ne].next=g[u]; 	g[u]=ne; } void init() { 	int u,v,w; 	cin>>n>>p>>c; 	for(int i=1;i<=n;i++)cin>>cow[i]; 	for(int i=1;i<=c;i++) 	   { 	   	  cin>>u>>v>>w; 	   	  insert(u,v,w); 	   	  insert(v,u,w); 	   } } void makenull() { 	for(int i=1;i<=p;i++) 	{ 	   pos[i]=num[i]=i; 	   dis[i]=0x7fffffff; }     size=p; } void sp(int a,int b) { 	int t=num[a];num[a]=num[b];num[b]=t;     pos[num[a]]=a;     pos[num[b]]=b; } void heapdown(int x) { 	int l=2*x,r=2*x+1; 	int mn; 	if(l<=size&&dis[num[l]]<dis[num[x]])mn=l;else mn=x;     if(r<=size&&dis[num[r]]<dis[num[mn]])mn=r;     if(mn!=x)     {     	sp(mn,x);         heapdown(mn);     } } void heapup(int x) {      while(x>1&&dis[num[x]]<dis[num[x/2]])     {        sp(x,x/2);        x=x/2;     } }  void dlt() { 	pos[num[1]]=-1;     num[1]=num[size];     pos[num[1]]=1;     size--;     heapdown(1); }  int main() { 	init(); 	int ans=0x7fffffff,now,sum; 	for(int i=1;i<=p;i++)     { 		makenull(); 		dis[i]=0; 		sp(i,1); 	for(int j=1;j<=p;j++) 	{ 		now=num[1]; 		dlt(); 		int k=g[now]; 		while(k>0) 		{ 		if(pos[e[k].v]!=-1&&dis[now]+e[k].w<dis[e[k].v])            {              dis[e[k].v]=dis[now]+e[k].w; 		     heapup(pos[e[k].v]);            }         k=e[k].next; 		} 	} 	sum=0;     for(int j=1;j<=n;j++) 	   sum+=dis[cow[j]];     if(sum<ans)ans=sum;     }     cout<<ans; 	return 0; } | 
最后把cin和cout都改成c语言的,速度没有明显变化
 
			
写STL的queue的spfa可以过的
为什么我写的结构体封装循环队列spfa就是比黄学长的手动循环队列时间长20%QAQ虽然都是只能过8个点
虽然现在已经过去很久了,但我就想吐槽一句黄学长你的前两个代码在codevs上都不过···第一个过了六个点第二个过了八个点···
本来就应该写dij+堆啊
一眨眼就有回复了···学长有没有SPFA的实现方法?→不过我想一定没有
印象中这题的本意就是要学习下dij。。。
窝用邻接表+spfa比堆优化dij还快
你在说笑吧
我写的跑了158ms,黄学长的跑了362ms……codes上有记录的,这题的图很稀疏,spfa理论上也应该超快的
哦,其实泥SPFA可以加两个优化(可以自行百度),会跑得飞快,图很稀疏推荐用前向星,反正系统的vector有点慢