zoukankan      html  css  js  c++  java
  • poj 3662 Telephone Lines

    题面

    解题思路

    这道题有两种方法可以做,第一种可以选择dp,与BZOJ 2763 飞行路线的做法相似。定义dp[x][i] 表示到了x这个点,用了i次免费的最小值,之后便可以在最短路中转移。我用的是spfa,时间复杂度O(NMt) t是一个常数,还是可以过得。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    
    using namespace std;
    const int MAXN = 1005;
    const int MAXM = 10005;
    const int inf = 0x3f3f3f3f;
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    
    int n,m,k;
    int head[MAXN],cnt;
    int to[MAXM<<1],nxt[MAXM<<1],val[MAXM<<1];
    int dp[MAXN][MAXN],ans=inf;
    queue<int> q;
    bool vis[MAXN];
    
    inline void add(int bg,int ed,int v){
        to[++cnt]=ed,val[cnt]=v,nxt[cnt]=head[bg],head[bg]=cnt;
    }
    
    inline void spfa(){
        vis[1]=1;dp[1][0]=0;q.push(1);
        while(q.size()){
            int x=q.front();q.pop();
            vis[x]=0;
            for(register int i=head[x];i;i=nxt[i]){
                int u=to[i];
                if(dp[u][0]>max(dp[x][0],val[i])){
                    dp[u][0]=max(dp[x][0],val[i]);
                    if(!vis[u]){
                        q.push(u);
                        vis[u]=1;
                    }
                }
                for(register int j=1;j<=k;j++){
                    if(dp[u][j]>min(dp[x][j-1],max(dp[x][j],val[i]))){
                        dp[u][j]=min(dp[x][j-1],max(dp[x][j],val[i]));
                        if(!vis[u]){
                            vis[u]=1;
                            q.push(u);
                        }
                    }
                } 
            }
        }
    }
    
    int main(){
        memset(dp,0x3f,sizeof(dp));
        n=rd();m=rd();k=rd();
        for(register int i=1;i<=m;i++){
            int x=rd(),y=rd(),z=rd();
            add(x,y,z);add(y,x,z);
        }spfa();
        for(register int i=0;i<=k;i++)
            ans=min(ans,dp[n][i]);
        if(ans==inf)  puts("-1");
        else printf("%d",ans);
        return 0; 
    }

    第二种做法是用二分答案,二分一个花费,之后把原图里花费比二分出的多的看做边权为1的边,少的看做边权为0的边,之后用一个双端队列bfs可以算出最短路。双端队列bfs的做法是如果这条边为1,就把要更新的点放到队尾,否则放在队首,时间复杂度O((N+M)log MAX_L),跑的更快一些

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<deque>
    
    using namespace std;
    const int MAXN = 1005;
    const int MAXM = 10005;
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
        return x*f;
    }
    
    int n,m,k,ans;
    int head[MAXN],cnt;
    int nxt[MAXM<<1],to[MAXM<<1],val[MAXM<<1];
    int mx,dis[MAXN];
    bool vis[MAXN];
    deque<int> q;
    
    inline void add(int bg,int ed,int v){
        nxt[++cnt]=head[bg],head[bg]=cnt,val[cnt]=v,to[cnt]=ed;
    }
    
    inline bool check(int len){
        memset(vis,false,sizeof(vis));
        memset(dis,0x3f,sizeof(dis));
        q.push_back(1);vis[1]=1;dis[1]=0;
        while(q.size()){
            int x=q.front();q.pop_front();
            for(register int i=head[x];i;i=nxt[i]){
                int u=to[i];
                if(val[i]<=len){
                    dis[u]=min(dis[u],dis[x]);
                    if(!vis[u]) q.push_front(u);
                }
                else if(val[i]>len){
                    dis[u]=min(dis[u],dis[x]+1);
                    if(!vis[u]) q.push_back(u); 
                } 
                vis[u]=1;
            }
        }
        if(dis[n]<=k) return true;
        return false;
    }
    
    int main(){
        n=rd();m=rd();k=rd();
        for(register int i=1;i<=m;i++){
            int x=rd(),y=rd(),z=rd();
            add(x,y,z);add(y,x,z);
            mx=max(z,mx);
        }
        int l=0,r=mx;
        while(l<=r){
            int mid=l+r>>1;
            if(check(mid))  ans=mid,r=mid-1;
            else l=mid+1;
        }
        if(!ans && !check(0)) puts("-1");
        else printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    elasticsearch之聚合函数
    elasticsearch之高亮查询
    elasticsearch之查询结果过滤
    elasticsearch之布尔查询
    elasticsearch之分页查询
    elasticsearch 之 排序查询
    elasticsearch 查询 term和match
    WSGI uwsgi wsgiref uWSGI werkzeug
    Django Contenttype组件
    迭代器
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9676970.html
Copyright © 2011-2022 走看看