北邮oj 468. 小妹妹送快递

思路

写了两种方法: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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值