思路
寫了兩種方法:dijkstra和kruskal
求最短路徑的變體,改一下鬆弛條件即可。
最坑的是當c=0時,輸出爲1.
題目
時間限制 1000 ms 內存限制 65536 KB
題目描述
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
Dijkstra AC代碼
#include <bits/stdc++.h>
using namespace std;
const int INF=INT_MAX/10;
const int MAXN=10005;
struct Edge{
int to;
int length;
Edge(int t,int l):to(t),length(l){}
};
struct Point{
int num;
int distance;
Point(int n,int d):num(n),distance(d){}
bool operator < (const Point& c)const{
return distance>c.distance;
}
};
vector<Edge>graph[MAXN];
int dis[MAXN];
void Dijkstra(int n)
{
dis[n]=0;
priority_queue<Point>myqueue;
myqueue.push(Point(n,dis[n]));
while(!myqueue.empty())
{
int u=myqueue.top().num;
myqueue.pop();
for(int i=0;i<graph[u].size();i++)
{
int v=graph[u][i].to;
int l=graph[u][i].length;
if(max(dis[u],l)<dis[v]) //修改鬆弛條件
{
dis[v]=max(dis[u],l);
myqueue.push(Point(v,dis[v]));
}
}
}
return ;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
long long m;
scanf("%d%lld",&n,&m);
memset(graph,0,sizeof(graph));
fill(dis,dis+n+1,INF);
for(long long i=0;i<m;i++)
{
int from,to,length;
scanf("%d%d%d",&from,&to,&length);
graph[from].push_back(Edge(to,length));
graph[to].push_back(Edge(from,length));
}
Dijkstra(1);
if(dis[n]==INF) printf("shimatta!\n");
else if(dis[n]==0) printf("1\n");
else printf("%d\n",dis[n]);
}
return 0;
}
kruskal AC代碼
#include <bits/stdc++.h>
using namespace std;
const int INF=INT_MAX/10;
const int MAXN=10005;
struct Edge{
int from;
int to;
int length;
bool operator <(const Edge& c)const{
return length<c.length;
}
};
Edge dis[100005];//邊的大小!很可能是開的太大了!
int father[MAXN];
int height[MAXN];
void Initial(int n)
{
for(int i=0;i<=n;i++)
{
father[i]=i;
height[i]=0;
}
return ;
}
int Find(int x)
{
if(x==father[x]) return x;
else return Find(father[x]);
}
void Union(int x,int y)
{
x=Find(x);
y=Find(y);
if(x!=y)
{
if(height[x]>height[y]) father[y]=x;
else if(height[x]<height[y]) father[x]=y;
else
{
father[y]=x;
height[x]++;
}
}
return ;
}
int Kruskal(long long m,int n)
{
int answer=0;
sort(dis,dis+m);
for(long long i=0;i<m;i++)
{
if(Find(1)!=Find(n))
{
if(Find(dis[i].from)!=Find(dis[i].to))
{
Union(dis[i].from,dis[i].to);
answer=max(answer,dis[i].length);
}
}
else return answer;
}
if(Find(1)==Find(n)) return answer;
else return INF;
//敲響警鐘!!!
//注意啊!!!最後一次剛好合成的邊界沒有考慮到!很多次題目都是這樣了!畢竟不好用flag判斷了
//再三強調!以後判斷出循環,一定要注意最後一個元素的情況!尤其是for中嵌套if的!
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
long long m;
scanf("%d%lld",&n,&m);
Initial(n);
memset(dis,0,sizeof(dis));
for(long long i=0;i<m;i++)
{
scanf("%d%d%d",&dis[i].from,&dis[i].to,&dis[i].length);
}
int answer=Kruskal(m,n);
if(answer==INF) printf("shimatta!\n");
else if(answer==0) printf("1\n");
else printf("%d\n",answer);
}
return 0;
}