最短路

 

Calling Circles

 UVA - 247

floyd+dfs

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<map>
 5 #include<string>
 6 #include<iostream>
 7 using namespace std;
 8 const int maxn=30;
 9 map<string,int> namecode;
10 string codename[maxn];
11 int p[maxn][maxn];
12 int vis[maxn];
13 int n,m;
14 void floyd()
15 {
16     for(int k=1;k<=n;k++)
17         for(int i=1;i<=n;i++)
18         if(p[i][k]) for(int j=1;j<=n;j++)
19          if(p[k][j]) p[i][j]=1;  
20 }
21 
22 void dfs(int u)
23 {
24     vis[u]=1;
25     for(int i=1;i<=n;i++)
26     if(!vis[i]&&p[u][i]&&p[i][u])
27         {
28         cout<<", "<<codename[i];
29         dfs(i);
30         }
31 }
32 int main()
33 {
34 
35    int cas=0;
36    string a,b;
37    while(scanf("%d%d",&n,&m)&&(n||m))
38    {
39        memset(p,0,sizeof(p));
40        memset(vis,0,sizeof(vis));
41        namecode.clear();
42        int id=0;
43        while(m--)
44        {
45            cin>>a>>b;
46            if(!namecode.count(a)) { namecode[a]=++id;codename[id]=a;  }
47            if(!namecode.count(b)) { namecode[b]=++id;codename[id]=b;  }
48            int u=namecode[a];
49            int v=namecode[b];
50            p[u][v]=1;
51        }
52        if(cas>1)  puts("");
53        printf("Calling circles for data set %d:\n",++cas);
54        floyd();
55        for(int i=1;i<=n;i++) if(!vis[i])
56        {
57           cout<<codename[i];
58            dfs(i);
59            puts("");
60        }
61       
62    }
63 }
View Code

 

昂贵的聘礼

 POJ - 1062 

关键在于枚举等级

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=110;
 7 const int inf=0x3f3f3f3f;
 8 int n,m;
 9 struct edge
10 {
11     int v,w,nex;
12 }e[maxn*maxn];
13 int head[maxn];
14 int cnt;
15 int dis[maxn];
16 int sta[maxn];
17 int ins[maxn];
18 int rk[maxn];
19 
20 void add(int u,int v,int w)
21 {
22     e[cnt].v=v;
23     e[cnt].w=w;
24     e[cnt].nex=head[u];
25     head[u]=cnt++;
26 }
27 
28 int  spfa(int s,int r)
29 {
30     for(int i=0;i<=n;i++)
31     {
32         dis[i]=inf;
33         ins[i]=0;
34     }
35     dis[s]=0;
36     ins[s]=1;
37     int top=0;
38     sta[top++]=s;
39     while(top)
40     {
41         int u=sta[--top];
42         ins[u]=0;
43         for(int i=head[u];i!=-1;i=e[i].nex)
44         {
45             int v=e[i].v;
46             if(rk[v]>m+r||rk[v]<r) continue;
47             int w=e[i].w;
48             if(dis[v]>dis[u]+w)
49             {
50                 dis[v]=dis[u]+w;
51                 if(!ins[v])
52                 {
53                     ins[v]=1;
54                     sta[top++]=v;
55                 }
56             }
57         }
58     }
59     return dis[1];
60 }
61 
62 int main()
63 {
64     scanf("%d%d",&m,&n);
65     int p,x,y;
66     cnt=0;
67     memset(head,-1,sizeof(head));
68     for(int i=1;i<=n;i++)
69     {
70         scanf("%d%d%d",&p,&rk[i],&x);
71         add(0,i,p);
72         for(int j=0;j<x;j++)
73         {
74             scanf("%d%d",&y,&p);
75             add(y,i,p);
76         }
77     }
78     int ans=inf;
79     for(int i=1;i<=n;i++) //枚举等级
80         ans=min(ans,spfa(0,rk[i]));
81     printf("%d\n",ans);
82 }
spfa
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <queue>
 5 using namespace std;
 6 const int maxn=110;
 7 const int inf=0x3f3f3f3f;
 8 struct Edge{
 9     int v,w,nex;
10 }e[maxn*maxn*2];
11 int head[maxn];
12 int cnt;
13 void init(){
14     memset(head,-1,sizeof(head));
15     cnt=0;
16 }
17 void add(int u,int v,int w){
18     e[cnt].v=v;
19     e[cnt].w=w;
20     e[cnt].nex=head[u];
21     head[u]=cnt++;
22 }
23 int n,m;
24 int r[maxn];
25 typedef pair<int,int> pii;
26 int d[maxn];
27 int dijkstra(int s,int g){
28     memset(d,inf,sizeof(d));
29     d[s]=0;
30     pii a=pii(0,s);
31     priority_queue< pii, vector<pii> ,greater<pii> > pq;
32     pq.push(a);
33     while(!pq.empty()){
34         pii b=pq.top();
35         pq.pop();
36         int u=b.second;
37         if(d[u]<b.first) continue;
38         for(int i=head[u];~i;i=e[i].nex){
39             int v=e[i].v;
40             if(r[v]>g+m||r[v]<g) continue;
41             if(d[v]>d[u]+e[i].w){
42                 d[v]=d[u]+e[i].w;
43                 pq.push(pii(d[v],v));
44             }
45         }
46     }
47     return d[1];
48 }
49 
50 
51 
52 int main(){
53     while(scanf("%d%d",&m,&n)!=EOF){
54         init();
55         int p,x;
56         for(int i=1;i<=n;i++){
57             scanf("%d%d%d",&p,&r[i],&x);
58             add(0,i,p);
59             int v;
60             for(int j=0;j<x;j++){
61                 scanf("%d%d",&v,&p);
62                 add(v,i,p);
63             }
64         }
65         int ans=inf;
66         for(int i=1;i<=n;i++){
67             ans=min(ans,dijkstra(0,r[i]));
68         }
69         printf("%d\n",ans);
70     }
71 }
堆优化dijkstra

 

 

scu4444

题目连接:https://vjudge.net/problem/SCU-4444

题意:n个点,其中有m条边的费用为a,其它边的费用为b,让求1到n的最小花费。m和n都<=1e5.

首先看连接1和n的是a边还是b边,分情况去计算另一种的费用,然后取较小的。

如果是a边,那么要考虑走b类边的费用,而b类边可能高达1e10条(几乎是完全图了),用bfs!用set保证每个点只入队一次!

如果是b边,考虑走a边的方案,dijkstra或者bellman_ford都可以

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<set>
  5 #include<algorithm>
  6 #define ll long long
  7 using namespace std;
  8 
  9 const int maxn=1e5+10;
 10 const int inf=0x3f3f3f3f;
 11 int head[maxn];
 12 int cnt=0;
 13 ll dis[maxn];
 14 
 15 int n,m;
 16 ll a,b;
 17 int u,v;
 18 
 19 struct edge
 20 {
 21     int v,w,nex;
 22 }e[maxn*10];
 23 struct node
 24 {
 25     int v;
 26     ll c;
 27     bool operator <(const node&a)const
 28     {
 29         return c>a.c;
 30     }
 31 };
 32 void init()
 33 {
 34     cnt=0;
 35    for(int i=0;i<=n;i++)
 36    {
 37        head[i]=-1;
 38    }
 39 }
 40 
 41 void add(int u,int v,int w)
 42 {
 43     e[cnt].v=v;
 44     e[cnt].w=w;
 45     e[cnt].nex=head[u];
 46     head[u]=cnt++;
 47 }
 48 ll dijkstra(int n)
 49 {
 50    for(int i=0;i<=n;i++)
 51         dis[i]=inf;
 52     priority_queue<node> pq;
 53     dis[1]=0;
 54     pq.push(node{1,0});
 55     while(!pq.empty())
 56     {
 57         node temp=pq.top();
 58         pq.pop();
 59         int u=temp.v;
 60         if(dis[u]<temp.c) continue;
 61         for(int i=head[u];i!=-1;i=e[i].nex)
 62         {
 63             int v=e[i].v;
 64             int w=e[i].w;
 65             if(dis[v]>dis[u]+w)
 66             {
 67                 dis[v]=dis[u]+w;
 68                 pq.push(node{v,dis[v]});
 69             }
 70         }
 71     }
 72     return dis[n];
 73 }
 74 
 75 ll bfs(int n,ll val)
 76 {
 77     set<int> ta,tb;
 78     queue<int>q;
 79     q.push(1);
 80     dis[1]=0;
 81     dis[n]=inf;
 82     for(int i=2;i<=n;i++) ta.insert(i);
 83     while(!q.empty())
 84     {
 85         int u=q.front();
 86         q.pop();
 87         for(int i=head[u];i!=-1;i=e[i].nex)
 88         {
 89             int v=e[i].v;
 90             if(!ta.count(v)) continue;
 91             ta.erase(v);
 92             tb.insert(v);
 93         }
 94         for(set<int>::iterator it=ta.begin();it!=ta.end();it++)
 95         {
 96             q.push(*it);
 97             dis[*it]=dis[u]+val;
 98         }
 99         ta.swap(tb);
100         tb.clear();
101     }
102     return dis[n];
103 }
104 int main()
105 {
106 
107     while(scanf("%d%d%lld%lld",&n,&m,&a,&b)!=EOF)
108     {
109         init();
110         int flag=0;
111         for(int i=0;i<m;i++)
112         {
113             scanf("%d%d",&u,&v);
114             add(u,v,a);
115             add(v,u,a);
116             if(min(u,v)==1&&max(u,v)==n) flag=1;
117         }
118         if(!flag) printf("%lld\n",min(dijkstra(n),b));
119         else printf("%lld\n",min(bfs(n,b),a));
120     }
121     return 0;
122 }
View Code

 

0 or 1

 HDU - 4370 

题意:题目给出了一个矩阵,其实是一个图,点i到点j的边权重为cij。让求满足1的楚都为1且n的入度为1的路径的最小值。

首先可以想到的是求最短路。

容易忽略的一种情况是1出发形成个环再回到1,n也是走一个环再回到n,也满足题意。

上述两种情况去较小的。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<queue>
 5 using namespace std;
 6 const int maxn=350;
 7 const int inf=0x3f3f3f3f;
 8 int n;
 9 int pic[maxn][maxn];
10 int dis[maxn];
11 int inq[maxn];
12 void spfa(int s)
13 {
14 
15     queue<int> q;
16     while(!q.empty()) q.pop();
17     for(int i=1;i<=n;i++)              
18     {
19         inq[i]=0;
20         if(i==s) dis[i]=inf; //求最小环
21         else {
22             dis[i]=pic[s][i];  //
23             inq[i]=1;
24             q.push(i);
25         }
26     }
27     while(!q.empty())
28     {
29         int u=q.front();
30         q.pop();
31         inq[u]=0;
32         for(int i=1;i<=n;i++)
33         {
34             if(dis[i]>dis[u]+pic[u][i])
35             {
36                 dis[i]=dis[u]+pic[u][i];
37 
38                 if(!inq[i])
39                 {
40                     inq[i]=1;
41                     q.push(i);
42                 }
43             }
44         }
45     }
46 
47 }
48 
49 int main()
50 {
51     while(scanf("%d",&n)!=EOF&&n)
52     {
53         for(int i=1;i<=n;i++)
54             for(int j=1;j<=n;j++)
55                 scanf("%d",&pic[i][j]);
56         spfa(1);
57         int s1=dis[1];  //1的最小环
58         int ans=dis[n];//1到n的最短路
59         spfa(n);
60         int s2=dis[n];// n的最小环
61         ans=min(ans,s1+s2);
62         printf("%d\n",ans);
63     }
64 }
View Code

 

题目连接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2031

首先判断图中是否存在环,若不存在则No cycle found.

若存在:

可知lowest mean的范围是介于最大权和最小权之间的。

可以二分,查找符合条件的最小值。

mid满足的条件是,存在k条边,使得w1+w2+w3+……+wk<k*mid;

上式可变形为 (w1-mid)+(w2-mid))+……+(wk-mid)<0; 即判断负环。

开始只判断了从1开始是否存在负环,WA几次才意识到问题,负环可能不含点1。。

虚拟一个结点0,到各个点距离为0. 从节点0开始入队即可查找全图是否存在负环。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 const double eps=1e-8;
  8 const int inf=0x3f3f3f3f;
  9 const int maxn=110;
 10 
 11 struct edge
 12 {
 13     int v,nex;
 14     double w;
 15 }e[maxn*maxn];
 16 
 17 int head[maxn],cnt=0;
 18 int inq[maxn],vis[maxn];
 19 double dis[maxn];
 20 int n,m;
 21 
 22 void add(int u,int v,double w)
 23 {
 24     e[cnt].v=v;
 25     e[cnt].w=w;
 26     e[cnt].nex=head[u];
 27     head[u]=cnt++;
 28 }
 29 int spfa()
 30 {
 31     queue<int> q;
 32     for(int i=1;i<=n;i++) //虚拟节点0
 33     {
 34         dis[i]=0;
 35         vis[i]=1;
 36         inq[i]=1;
 37         q.push(i);
 38     }
 39     while(!q.empty())
 40     {
 41         int u=q.front();
 42         q.pop();
 43         inq[u]=0;
 44         for(int i=head[u];i!=-1;i=e[i].nex)
 45         {
 46             int v=e[i].v;
 47             if(dis[v]>dis[u]+e[i].w)
 48             {
 49                 dis[v]=dis[u]+e[i].w;
 50                 if(!inq[v])
 51                 {
 52                     inq[v]=1;
 53                     vis[v]++;
 54                     if(vis[v]>n) return 1;
 55                     q.push(v);
 56                 }
 57             }
 58         }
 59     }
 60     return 0;
 61 }
 62 int check(double x)
 63 {
 64     int ok=0;
 65     for(int i=0;i<cnt;i++)
 66         e[i].w-=x;
 67     if(spfa()) ok=1;
 68     for(int i=0;i<cnt;i++)
 69         e[i].w+=x;
 70     return ok;
 71 }
 72 int main()
 73 {
 74     int t;
 75     scanf("%d",&t);
 76     for(int c=1;c<=t;c++)
 77     {
 78         int u,v;
 79         double w,L=inf,R=0;
 80         memset(head,-1,sizeof(head));
 81         cnt=0;
 82         scanf("%d%d",&n,&m);
 83         for(int i=0;i<m;i++)
 84         {
 85             scanf("%d%d%lf",&u,&v,&w);
 86             add(u,v,w);
 87             L=min(L,w);
 88             R=max(R,w);
 89         }
 90         printf("Case #%d: ",c);
 91         if(!check(1+R))
 92             puts("No cycle found.");
 93         else
 94         {
 95             while(R-L>eps)
 96             {
 97                 double mid=L+(R-L)/2;
 98                 if(check(mid)) R=mid;
 99                 else L=mid;
100             }
101             printf("%.2lf\n",R);
102         }
103     }
104     return 0;
105 }
spfa

 

poj1511

题目连接:http://poj.org/bbs?problem_id=1511

求1到各点再回到1的最短路之和。

数据太大,只能用spfa??

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 #include<stack>
 5 using namespace std;
 6 #define ll long long
 7 const int maxn=1000010;
 8 const int inf=0x3f3f3f3f;
 9 int head[maxn];
10 int inq[maxn];
11 ll dis[maxn];
12 int n,m,t;
13 int u,v,w;
14 struct node
15 {
16     int u,v,w;
17     int nex;
18 }e[maxn],tmp[maxn];
19 int cnt;
20 
21 void add(int u,int v,int w)
22 {
23     e[cnt].u=u;
24     e[cnt].v=v;
25     e[cnt].w=w;
26     e[cnt].nex=head[u];
27     head[u]=cnt++;
28 }
29 ll spfa()
30 {
31     stack<int>q;
32     for(int i=1;i<=n;i++)
33     {
34         inq[i]=0;
35         dis[i]=inf;
36     }
37     dis[1]=0;
38     inq[1]=1;
39     q.push(1);
40     while(!q.empty())
41     {
42         int x=q.top();
43         q.pop();
44         inq[x]=0;
45         for(int i=head[x];i!=-1;i=e[i].nex)
46         {
47             if(dis[e[i].v]>dis[x]+e[i].w)
48             {
49                 dis[e[i].v]=dis[x]+e[i].w;
50                 if(!inq[e[i].v])
51                 {
52                     q.push(e[i].v);
53                     inq[e[i].v]=1;
54                 }
55             }
56         }
57     }
58     ll res=0;
59     for(int i=1;i<=n;i++)
60         res+=dis[i];
61     return res;
62 }
63 int main()
64 {
65     scanf("%d",&t);
66     while(t--)
67     {
68         cnt=0;
69         scanf("%d%d",&n,&m);
70         memset(head,-1,sizeof(head));
71         for(int i=0;i<m;i++)
72         {
73             scanf("%d%d%d",&tmp[i].u,&tmp[i].v,&tmp[i].w);
74             add(tmp[i].u,tmp[i].v,tmp[i].w);
75         }
76         ll s1=spfa();
77         memset(head,-1,sizeof(head));
78         cnt=0;
79         for(int i=0;i<m;i++)
80             add(tmp[i].v,tmp[i].u,tmp[i].w);
81          ll s2=spfa();
82          printf("%lld\n",s1+s2);
83 
84 
85     }
86 }
View Code

 

Steam Roller

 UVALive - 4128 
反正我是根本不会建图=_=||
看了好久大概看明白一点。。。
  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define CLR(m,a) memset(m,a,sizeof(m))
  4 typedef pair<int,int> PII;
  5 const int inf=0x3f3f3f3f;
  6 const int maxv=80010;
  7 const int maxe=330000;
  8 
  9 struct Edge{
 10     int v,w;
 11     int nex;
 12     Edge(int v=0,int w=0,int nex=0):
 13         v(v),w(w),nex(nex){}
 14 }e[maxe];
 15 int head[maxv];
 16 int cnt=0;
 17 void init()
 18 {
 19     CLR(head,-1);
 20     cnt=0;
 21 }
 22 void add(int u,int v,int w)
 23 {
 24     e[cnt]=Edge(v,w,head[u]);
 25     head[u]=cnt++;
 26 }
 27 
 28 int dis[maxv];
 29 void dijkstra(int s)
 30 {
 31     priority_queue<PII,vector<PII> ,greater<PII> > pq;
 32     CLR(dis,inf);
 33     dis[s]=0;
 34     pq.push(PII(0,s));
 35     while(!pq.empty()){
 36         PII tp=pq.top();
 37         pq.pop();
 38         int u=tp.second;
 39         if(dis[u]<tp.first) continue;
 40         for(int i=head[u];~i;i=e[i].nex){
 41             int v=e[i].v;
 42             if(dis[v]>dis[u]+e[i].w){
 43                 dis[v]=dis[u]+e[i].w;
 44                 pq.push(PII(dis[v],v));
 45             }
 46         }
 47     }
 48 }
 49 
 50 int R,C,r1,c1,r2,c2;
 51 const int UP=0, LEFT=1, DOWN=2, RIGHT=3 ; //各方向的名字
 52 const int inv[]={2,3,0,1}; //每个方向的反方向
 53 const int dr[]={-1,0,1,0}; //每个方向对应的“行编号”的增量
 54 const int dc[]={0,-1,0,1}; //每个方向对应的“列编号”的增量
 55 const int maxr=100;
 56 const int maxc=100;
 57 
 58 int grid[maxr][maxc][4]; //grid[r][c][dir]代表从交叉点(r,c)出发,dir方向的边权
 59 int n,id[maxr][maxc][4][2]; //节点总数,状态(r,c,dir,doubled)的编号
 60 
 61 //给状态(r,c,dir,doubled)编号
 62 int ID(int r,int c,int dir,int doubled)
 63 {
 64     int &x=id[r][c][dir][doubled];
 65     if(x==0) x=++n;  //从1开始编号
 66     return x;
 67 }
 68 
 69 //是否可以从交叉点(r,c)沿着dir方向走
 70 bool cango(int r,int c,int dir)
 71 {
 72     if(r<0||r>=R||c<0||c>=C) return 0;
 73     return grid[r][c][dir]>0;  //0不可走
 74 }
 75 
 76 int readint(){
 77     int x;
 78     scanf("%d",&x);
 79     return x;
 80 }
 81 
 82 int main()
 83 {
 84     int kase=0;
 85     while(scanf("%d%d%d%d%d%d",&R,&C,&r1,&c1,&r2,&c2)!=EOF&&R){
 86         init();
 87         r1--;c1--;r2--;c2--;
 88         //每个方格的左上角为基准上下左右
 89         for(int r=0;r<R;r++){
 90             for(int c=0;c<C-1;c++){
 91                 grid[r][c][RIGHT]=grid[r][c+1][LEFT]=readint();
 92             }
 93             if(r!=R-1) for(int c=0;c<C;c++){
 94                 grid[r][c][DOWN]=grid[r+1][c][UP]=readint();
 95             }
 96         }
 97         n=0;
 98         CLR(id,0);
 99 
100         //从源点出发的边
101         for(int dir=0;dir<4;dir++) if(cango(r1,c1,dir)){
102             add(0,ID(r1+dr[dir],c1+dc[dir],dir,1),grid[r1][c1][dir]*2);
103         }
104         //计算每个(r,c,dir,doubled)的后继状态
105         for(int r=0;r<R;r++){
106             for(int c=0;c<C;c++){
107                 for(int dir=0;dir<4;dir++) if(cango(r,c,inv[dir])){
108                     for(int newdir=0;newdir<4;newdir++)if(cango(r,c,newdir)){
109                         for(int doubled=0;doubled<2;doubled++){
110                             int newr=r+dr[newdir];
111                             int newc=c+dc[newdir];
112                             int v=grid[r][c][newdir],newdoubled=0;
113                             if(dir!=newdir){
114                                 if(!doubled) v+=grid[r][c][inv[dir]]; //老边加倍
115                                 newdoubled=1;v+=grid[r][c][newdir]; //新边加倍
116                             }
117                             add(ID(r,c,dir,doubled),ID(newr,newc,newdir,newdoubled),v);
118                         }
119                     }
120                 }
121             }
122         }
123         dijkstra(0);
124         int ans=inf;
125         for(int dir=0;dir<4;dir++) if(cango(r2,c2,inv[dir])){
126             for(int doubled=0;doubled<2;doubled++){
127                 int v=dis[ID(r2,c2,dir,doubled)];
128                 if(!doubled) v+=grid[r2][c2][inv[dir]];
129                 ans=min(ans,v);
130             }
131         }
132         printf("Case %d: ",++kase);
133         if(ans==inf) puts("Impossible");
134         else printf("%d\n",ans);
135     }
136     return 0;
137 }
View Code

 

posted @ 2017-07-27 00:28  yijiull  阅读(147)  评论(0编辑  收藏  举报