468. 小妹妹送快递
题目描述
Mays王国的女王大人每天过着自由自在的生活,她最大的乐趣就是给邻国的帅气王子写信。但是最近,Mays王国的叔叔们变得很无聊,他们知道女王大人每次都把信委托给皇家小妹妹快递公司的小妹妹们,于是叔叔们给每一条路都设立了路障,只有小妹妹们给他们表演节目才会让小妹妹们过去。
在每一个路障,都有不同数量的叔叔,只有表演的小妹妹的数量不少与叔叔的数量的时候叔叔才会放她们过去。
为了节省开销,小妹妹快递公司希望派最少的小妹妹把女王大人的信件送到。请你告诉他们需要派几个小妹妹。
输入格式
输入第一行为数据组数T(T<=10),接下来T组数据,每组第一行为n,m,,2<=n<=10000,1<=m<=100000,表示Mays王国的道路由n个节点组成,接下来m行,每行一组u,v,c表示连接节点u,v的一条无向道路,且路障上有c个叔叔,1<=u,v<=n,0<=c<=100。女王大人和皇家小妹妹快递公司都在节点1,帅气的邻国王子住在节点n。
输出格式
每组数据输出一个数字,表示小妹妹快递公司最少需要派出的小妹妹数量。如果无论派出多少小妹妹都无法把信送到帅气的邻国王子手里,输出"shimatta!"。
输入样例
1
3 3
1 2 1
2 3 1
1 3 3
输出样例
1
赛中提交:RE RE RE RE WA WA
赛后AC:Y
总结&反省:
(1)赛中的时候RE了好多次,还有之前的一道也是用了静态邻接链表+SPFA的题目,也是RE
这两次都是先一直以为是存边的G开小了,结果改了边一直没过,最后是改了存点的maxn过了
后来也一直没有搞清楚原因,直到问了某翔,他指出是队列数组超了,
原因是,假设某个点向外一共连有e条边,那么当我们每选中那e个点中的一个,都会让这个入队一次
也就是说入队的总点数是maxe,所以最保险的是把队列数组开得比边的最大数量大一点
(2)其次是这个题目的一个大坑,当所有的路的权值都为0时,这个时候spfa输出的值是0....
但是你还是需要一个人送出去的对不对~!?!?!!?!?
(3)说说思路,其实在赛中思路是已经自己给出来了的,
那就是将松弛的对象(d[i]原来表示某点都达源点的最短距离)改成所选择路径上所有边中的最大权值
也就是说“d[i]表示从i到达源点的路径上所有边中的最大权值”
下面是AC代码:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 10005
#define maxe 200005
using namespace std;
struct edge{
int to,next,cost;
};
edge G[maxe];
int si,head[maxn],vis[maxn];
int n,m;
int dis[maxn];
int q[maxe];
void add_edge(int u,int v,int cost)
{
G[si].to=v;
G[si].next=head[u];
G[si].cost=cost;
head[u]=si++;
}
void spfa(int start)
{
for(int i=1;i<=n;i+=1){
dis[i]=999999999;
}
int i,hea=0,tail=1;
q[hea]=start;
dis[start]=0;
vis[start]=1;
while(hea<tail){
int from=q[hea++];
vis[from]=0;
for(int i=head[from];i!=-1;i=G[i].next){
int to=G[i].to;
if(dis[to]>max(dis[from],G[i].cost)){
dis[to]=max(dis[from],G[i].cost);
if(!vis[to]){
q[tail++]=to;
vis[to]=1;
}
}
}
}
if(!dis[n]){
printf("shimatta!\n");
}
else{
printf("%d\n",dis[n]);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
bool flag=false;
si=0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
scanf("%d %d",&n,&m);
for(int i=0;i<m;i+=1){
int u,v,cost;
scanf("%d %d %d",&u,&v,&cost);
if(cost){
flag=true;
}
add_edge(u,v,cost);
add_edge(v,u,cost);
}
if(!flag){
printf("1\n");
}
else{
spfa(1);
}
}
return 0;
}