Sweet Butter 香甜的黄油
题目大意:m个点,n头奶牛,p条边,每一头奶牛在一个点上,一个点可以有多只奶牛,求这样一个点,使得所有奶牛到这个点的距离之和最小。
注释:n<=500 , m<=800 , p<=1450 , 连边的牧场之间的距离d<=255
想法:显然,这是一个最短路问题,有两种途径:1. 跑多源最短路。2. 跑m遍单源最短路。
第1种想法想到floyd , 时间复杂度O(m^3)=O(5.12*10^8),过不去,用第二种想法吧。
由于floyd都T了,n遍Dijkstra的时间复杂度也是O(m^3),而另一种单源最短路是spfa,时间复杂度O(m*p+m*n)。所以,spfa才是我们想要的算法。
首先,对于每一个节点跑一遍spfa,注意清数组。存边用邻接矩阵或链式前向星均可,博主在此采用链式前向星。
最后,附上丑陋的代码...
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 using namespace std; 6 queue<int>q; 7 int f[10010],a[10010]; 8 bool v[10010]; 9 int to[10010],val[10010],next[10010],head[10010],tot; 10 void add(int x,int y,int z)//存边 11 { 12 to[++tot]=y; 13 val[tot]=z; 14 next[tot]=head[x]; 15 head[x]=tot; 16 } 17 void spfa(int xp)//spfa,xp表示当前枚举的源点 18 { 19 memset(f,0x3f,sizeof(f)); 20 memset(v,0,sizeof(v)); 21 q.push(xp),f[xp]=0,v[xp]=1; 22 while(q.size()) 23 { 24 int x,y; 25 x=q.front(),q.pop(),v[x]=0; 26 for(int i=head[x];i;i=next[i]) 27 { 28 if(f[y=to[i]]>f[x]+val[i]) 29 { 30 f[y]=f[x]+val[i]; 31 if(v[y]==0) q.push(y),v[y]=1; 32 } 33 } 34 } 35 } 36 int main() 37 { 38 int n,m,p; 39 scanf("%d%d%d",&n,&m,&p); 40 for(int i=1;i<=n;i++) 41 { 42 scanf("%d",&a[i]); 43 } 44 int fr,t,va; 45 for(int i=1;i<=p;i++) 46 { 47 scanf("%d%d%d",&fr,&t,&va); 48 add(fr,t,va);//存双向边 49 add(t,fr,va);//存双向边 50 } 51 long long minn=9220000000000000ll; 52 for(int i=1;i<=m;i++) 53 { 54 spfa(i); 55 long long ans=0; 56 for(int j=1;j<=n;j++) 57 { 58 ans+=f[a[j]]; 59 } 60 minn=min(ans,minn); 61 } 62 printf("%lld",minn); 63 return 0; 64 }
小结,错误
1.双向边,双向边,双向边
2.line 60:写成了 ans=min ( minn , ans ) 全盘爆蛋
3.因为本题不一定连通,所以在一定程度上我们需要考虑不连通的情况,所以ans和minn开long long 来解决。