zoukankan      html  css  js  c++  java
  • 挑战程序设计竞赛 2.5 它们其实都是“图”

    【Summarize】

      1.注意对图是否连通的判定

      2.灵活运用边权取负的技巧

    AOJ 0189:Convenient Location

    /*
        给出一张无向图,现在求一个点,使得这个点到所有点的距离和最小
        输出这个点的编号和距离和
    */
    #include <cstdio>
    #include <algorithm>
    #include <cstring> 
    using namespace std;
    const int N=10,INF=0x3f3f3f3f;
    int n,d[N][N],c,x,y,m;
    int main(){
        while(~scanf("%d",&m),m){
            memset(d,INF,sizeof(d)); n=0;
            while(m--){
                scanf("%d%d%d",&x,&y,&c);
                d[x][y]=d[y][x]=c;
                n=max(n,max(x,y));
            }
            for(int k=0;k<=n;k++)
                for(int i=0;i<=n;i++)
                    for(int j=0;j<=n;j++)d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
            int ans=INF,pos=0;
            for(int i=0;i<=n;i++){
                int tmp=0;
                for(int j=0;j<=n;j++)if(i!=j)tmp+=d[i][j];
                if(tmp<ans)ans=tmp,pos=i;
            }printf("%d %d
    ",pos,ans);
        }return 0;
    }

    POJ 2139:Six Degrees of Cowvin Bacon

    /*
        求一头奶牛到其它奶牛的平均距离的100倍的最小值
    */
    #include <cstdio>
    #include <algorithm>
    #include <cstring> 
    using namespace std;
    const int N=310,INF=0x3f3f3f3f;
    int n,d[N][N],c,x,y,m,a[N];
    int main(){
        while(~scanf("%d%d",&n,&m)){
            memset(d,INF,sizeof(d)); 
            while(m--){
                scanf("%d",&c);
                for(int i=1;i<=c;i++)scanf("%d",&a[i]),a[i]--;
                for(int i=1;i<=c;i++)for(int j=1;j<i;j++)d[a[i]][a[j]]=d[a[j]][a[i]]=1;
            }
            for(int k=0;k<n;k++)
                for(int i=0;i<n;i++)
                    for(int j=0;j<n;j++)d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
            int ans=INF;
            for(int i=0;i<n;i++){
                int tmp=0;
                for(int j=0;j<n;j++)if(i!=j)tmp+=d[i][j];
                if(tmp<ans)ans=tmp;
            }printf("%d
    ",100*ans/(n-1));
        }return 0;
    }

    POJ 3268:Silver Cow Party

    /*
        在有向图中求每个点到终点后返回的最短路的最大值
        以终点为源点做一次正向路径的spfa和一次反向路径的spfa,
        相加即为每个点的答案
    */
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int N=200010,inf=~0U>>2,M=200000;
    int T,tim[N],q[N],size,h,t,n,m,x,ed[2],dis[2][N],in[N],nxt[2][N],w[2][N],v[2][N],g[2][N],u,e,cost;
    void add(int u,int x,int y,int z){v[u][++ed[u]]=y;w[u][ed[u]]=z;nxt[u][ed[u]]=g[u][x];g[u][x]=ed[u];}
    int spfa(int u,int S){
        for(int i=1;i<=n;i++)dis[u][i]=inf,in[i]=0,tim[i]=0;
        tim[S]=1,dis[u][S]=0,in[S]=1;
        int i,x,size; q[h=t=size=1]=S;
        while(size){
            for(i=g[u][x=q[h]],h=(h+1)%M,size--;i;i=nxt[u][i])if(dis[u][x]+w[u][i]<dis[u][v[u][i]]){
                dis[u][v[u][i]]=dis[u][x]+w[u][i];
                if(!in[v[u][i]]){
                    tim[v[u][i]]++,t=(t+1)%M,size++,in[q[t]=v[u][i]]=1;
                    if(tim[v[u][i]]>n)return -1;
                }
            }in[x]=0;
        }
    }
    int main(){
        scanf("%d%d%d",&n,&m,&x);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&u,&e,&cost);
            add(0,u,e,cost);
            add(1,e,u,cost);    
        }spfa(1,x);spfa(0,x);
        int ans=0;
        for(int i=1;i<=n;i++)ans=max(dis[0][i]+dis[1][i],ans);
        return printf("%d
    ",ans),0;
    }

    POJ 3259:Wormholes

    /*
        给出一张n个点m条边的无向图,有w个虫洞,可以在穿越的过程中减少时间
        问有没有可能回到过去
        回到过去即存在负权回路,SPFA求解即可
        需要注意的是不是连通图,因此在做spfa的时候要将所有的点先入队一次
    */
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=200010,inf=~0U>>2,M=200000;
    int x,S,T,time[N],q[N],size,h,t,n,m,W,ed,dis[N],in[N],nxt[N],w[N],v[N],g[N],u,e,cost;
    void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
    int spfa(int S){
        for(int i=1;i<=n;i++)dis[i]=inf,in[i]=0,time[i]=0;
        time[S]=1,dis[S]=0,in[S]=1;
        int i,x,size; q[h=t=size=1]=S;
        for(int i=1;i<=n;i++){time[i]++,t=(t+1)%M,size++,in[q[t]=i]=1;}
        while(size){
            for(i=g[x=q[h]],h=(h+1)%M,size--;i;i=nxt[i])if(dis[x]+w[i]<dis[v[i]]){
                dis[v[i]]=dis[x]+w[i];
                if(!in[v[i]]){
                    time[v[i]]++,t=(t+1)%M,size++,in[q[t]=v[i]]=1;
                    if(time[v[i]]>n)return -1;
                }
            }in[x]=0;
        }return dis[T];
    }int cas;
    int main(){
        scanf("%d",&cas);
        while(cas--){
            scanf("%d%d%d",&n,&m,&W);
            memset(v,0,sizeof(v)); memset(nxt,0,sizeof(nxt));
            memset(w,0,sizeof(w)); memset(g,0,sizeof(g)); ed=0;
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&u,&e,&cost);
                add(u,e,cost);
                add(e,u,cost);
            }
            for(int i=1;i<=W;i++){
                scanf("%d%d%d",&u,&e,&cost);
                add(u,e,-cost);
            }
            if(spfa(1)==-1)puts("YES"); 
            else puts("NO");
        }return 0;
    }

    AOJ 2249:Road Construction

    /*
        建造每条道路需要的费用已经给出,
        现在求在起点到每个点都是最短路的情况下的最小修路费用
        考虑到最后一定是树形的,因此只要保留每个点与其父节点之间的边的费用最小值即可
        在计算最短路的同时不断更新费用
    */
    #include <cstdio>  
    #include <cstring> 
    #include <queue> 
    #include <utility> 
    using namespace std;  
    const int N=2000100;  
    const int INF=~0U>>2;  
    typedef pair<int,int>seg;  
    priority_queue<seg,vector<seg>,greater<seg> >q;     
    int d[N],D[N],head[N],u[N],v[N],w[N],nxt[N],cost[N],n,m,a,b,c,cc,ed=0,H,x[N],y[N]; 
    bool vis[N];  
    void add(int a,int b,int c,int cos){  
        u[++ed]=a,v[ed]=b,w[ed]=c;cost[ed]=cos;
        nxt[ed]=head[u[ed]]; head[u[ed]]=ed;     
    }     
    void Dijkstra(int src){  
        memset(vis,0,sizeof(vis));  
        for(int i=1;i<=n;i++)d[i]=INF;  
        d[src]=0;  
        q.push(make_pair(d[src],src));  
        while(!q.empty()){  
            seg now=q.top(); q.pop();  
            int x=now.second;  
            if(d[x]<now.first)continue; 
            for(int e=head[x];e!=-1;e=nxt[e]) 
            if(d[v[e]]>d[x]+w[e]){ 
                d[v[e]]=d[x]+w[e];  
                D[v[e]]=cost[e];
                q.push(make_pair(d[v[e]],v[e]));  
            }else if(d[v[e]]==d[x]+w[e]){
                D[v[e]]=min(cost[e],D[v[e]]);
            }
        }
    } 
    int main(){
    	  while(~scanf("%d%d",&n,&m),m+n){
    		    memset(head,-1,sizeof(head));ed=0;
    		    memset(nxt,-1,sizeof(nxt));
    	      while(m--){
    	    	    scanf("%d%d%d%d",&a,&b,&c,&cc);
    	    	    add(a,b,c,cc);add(b,a,c,cc);
    	      }Dijkstra(1);
    	      int ans=0;
    	      for(int i=2;i<=n;i++)ans+=D[i];
    		    printf("%d
    ",ans);
    	  }return 0;
    }

    AOJ 2200:Mr. Rito Post Office

    /*
        一张图中有陆路和水路,水路必须要有船才能走,当船开到x点时就会停在x点
        一开始人和船都在1点,问按给出顺序访问一些点需要的最短时间
        利用floyd可以得出只走陆路和只走水路时两点间的最短路
        dp[i][j]表示走到了第i个需要访问的村庄,船停在j点的最短路,然后顺序dp更新状态即可
    */
    #include <cstdio>
    #include <algorithm>
    #include <cstring> 
    #define rep(i,n) for(int i=1;i<=n;i++)
    using namespace std;
    typedef long long LL;
    const int INF=0x3f3f3f3f;
    int n,m,q,x,y,z,d[1010]; char c;
    int dl[210][210],ds[210][210],dp[1010][210];
    int main(){
        while(~scanf("%d%d",&n,&m),n+m){
            rep(i,n)rep(j,n)ds[i][j]=dl[i][j]=i==j?0:INF;
            rep(i,m){
                scanf("%d%d%d %c",&x,&y,&z,&c);
                if(c=='S')ds[x][y]=ds[y][x]=min(ds[x][y],z);
                else dl[x][y]=dl[y][x]=min(dl[x][y],z);
            }scanf("%d",&q);
            rep(i,q)scanf("%d",d+i);
            rep(k,n)rep(i,n)rep(j,n){
                ds[i][j]=min(ds[i][j],ds[i][k]+ds[k][j]);
                dl[i][j]=min(dl[i][j],dl[i][k]+dl[k][j]);
            }memset(dp,INF,sizeof(dp));
            dp[1][d[1]]=0;
            rep(i,q)rep(j,n){
                dp[i][j]=min(dp[i][j],dp[i-1][j]+dl[d[i-1]][d[i]]);
                rep(k,n)dp[i][k]=
                    min((LL)dp[i][k],(LL)dp[i-1][j]+dl[d[i-1]][j]+ds[j][k]+dl[k][d[i]]);  
            }printf("%d
    ",*min_element(dp[q],dp[q]+n+1));
        }return 0;
    }

    POJ 1258:Agri-Net

    /*
        裸最小生成树
    */
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    struct data{int x,y,c;}p[20010];  
    int n,m,f[110],x;
    bool cmp(data a,data b){return a.c<b.c;}
    int sf(int x){return x==f[x]?x:f[x]=sf(f[x]);}
    int main(){  
        while(~scanf("%d",&n)){
        	  m=0;
            for(int i=1;i<=n;i++)f[i]=i; 
            for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
                scanf("%d",&x);
                if(i<j){p[++m].c=x;p[m].x=i;p[m].y=j;}
            }sort(p+1,p+m+1,cmp);
            int ans=0;
            for(int i=1;i<=m;i++){
                if(sf(p[i].x)!=sf(p[i].y)){
                    ans+=p[i].c;
                    f[sf(p[i].x)]=sf(p[i].y);
                }
            }printf("%d
    ",ans);
    	  }return 0;  
    }  

    POJ 2377:Bad Cowtractors

    /*
        裸最大生成树,需要注意判断无解的情况
    */
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    struct data{int x,y,c;}p[20010];  
    int n,m,f[1010],x;
    bool cmp(data a,data b){return a.c>b.c;}
    int sf(int x){return x==f[x]?x:f[x]=sf(f[x]);}
    int main(){
        while(~scanf("%d%d",&n,&m)){
            for(int i=1;i<=n;i++)f[i]=i;
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].c);
            }sort(p+1,p+m+1,cmp);
            int ans=0,cnt=1;
            for(int i=1;i<=m;i++){
                if(sf(p[i].x)!=sf(p[i].y)){
                    ans+=p[i].c;
                    cnt++;
                    f[sf(p[i].x)]=sf(p[i].y);
                }
            }if(cnt!=n)puts("-1");
            else printf("%d
    ",ans);
        }return 0;
    }

    AOJ 2224:Save your cats

    /*
        删除一些边使得图中没有环,求删除边的最小代价
    */
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const int N=100100;
    int n,m,a,b,x[N],y[N],f[N];
    struct data{int x,y;double c;}p[N];
    bool cmp(data a,data b){return a.c<b.c;}
    int sf(int x){return f[x]==x?x:f[x]=sf(f[x]);}
    int sqr(int x){return x*x;}
    int main(){
        while(~scanf("%d%d",&n,&m)){
            double sum=0;
            for(int i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]),f[i]=i;
            for(int i=1;i<=m;i++){
                scanf("%d%d",&a,&b);
                double c=sqrt(sqr(x[a]-x[b])+sqr(y[a]-y[b]));
                sum+=c;
                p[i].x=a;p[i].y=b;
                p[i].c=-c;
            }sort(p+1,p+m+1,cmp);
            for(int i=1;i<=m;i++){
                if(sf(p[i].x)!=sf(p[i].y)){
                    sum+=p[i].c;
                    f[sf(p[i].x)]=sf(p[i].y);
                }
            }printf("%.3f
    ",sum);
        }return 0;
    }

    POJ 2395:Out of Hay

    /*
        求最小生成树中的最大边权
    */
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    struct data{int x,y,c;}p[20010];  
    int n,m,f[2010],x;
    bool cmp(data a,data b){return a.c<b.c;}
    int sf(int x){return x==f[x]?x:f[x]=sf(f[x]);}
    int main(){
        while(~scanf("%d%d",&n,&m)){
            for(int i=1;i<=n;i++)f[i]=i;
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].c);
            }sort(p+1,p+m+1,cmp);
            int ans=0;
            for(int i=1;i<=m;i++){
                if(sf(p[i].x)!=sf(p[i].y)){
                    ans=max(ans,p[i].c);
                    f[sf(p[i].x)]=sf(p[i].y);
                }
            }printf("%d
    ",ans);
        }return 0;
    }
  • 相关阅读:
    With在sql server 2005中的用法
    相互关联子查询在项目中的用法
    存储过程中@@Identity全局变量
    sql server 2008 5120错误
    如何启用 FILESTREAM
    表变量在存储过程或sql server中的运用
    Union ,Union ALL的用法
    数据移植(利用Ado.Net功能实现)
    Foreign Key ,NO action,Cascade的用法
    EXISTS 在SQL 中的用法
  • 原文地址:https://www.cnblogs.com/forever97/p/6092200.html
Copyright © 2011-2022 走看看