最短路拓展
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=1e6+10; 8 const int inf=1e9; 9 struct node{ 10 int v; 11 int c; 12 node(int _v=0,int _c=0):v(_v),c(_c) {} 13 bool operator < (const node &r)const{ 14 return c>r.c; 15 } 16 }; 17 struct Edge{ 18 int v,cost; 19 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 20 }; 21 vector<Edge>E[maxn]; 22 bool vis[maxn]; 23 int dist[maxn]; 24 int n,s; 25 26 void addedge(int u,int v,int w) 27 { 28 E[u].push_back(Edge(v,w)); 29 } 30 31 void dij() 32 { 33 memset(vis,false,sizeof(vis)); 34 for ( int i=1;i<=n;i++ ) dist[i]=inf; 35 priority_queue<node>que; 36 while ( !que.empty() ) que.pop(); 37 dist[s]=0; 38 que.push(node(s,0)); 39 node tmp; 40 while ( !que.empty() ) 41 { 42 tmp=que.top(); 43 que.pop(); 44 int u=tmp.v; 45 if ( vis[u] ) continue; 46 vis[u]=true; 47 for ( int i=0;i<E[u].size();i++ ) 48 { 49 int v=E[u][i].v; 50 int cost=E[u][i].cost; 51 if ( !vis[v] && dist[v]>dist[u]+cost ) 52 { 53 dist[v]=dist[u]+cost; 54 que.push(node(v,dist[v])); 55 } 56 } 57 } 58 }
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=1010; 8 const int inf=1e9; 9 struct Edge{ 10 int v; 11 int cost; 12 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 13 }; 14 vector<Edge>E[maxn]; 15 bool vis[maxn]; 16 int cnt[maxn]; 17 int dist[maxn]; 18 int s,n; 19 20 void addedge(int u,int v,int w) 21 { 22 E[u].push_back(Edge(v,w)); 23 } 24 25 bool spfa() 26 { 27 memset(vis,false,sizeof(vis)); 28 for ( int i=1;i<=n;i++ ) dist[i]=inf; 29 vis[s]=true; 30 dist[s]=0; 31 queue<int>que; 32 while ( !que.empty() ) que.pop(); 33 que.push(s); 34 memset(cnt,0,sizeof(cnt)); 35 cnt[s]=1; 36 while ( !que.empty() ) 37 { 38 int u=que.front(); 39 que.pop(); 40 vis[u]=false; 41 for ( int i=0;i<E[u].size();i++ ) 42 { 43 int v=E[u][i].v; 44 int cost=E[u][i].cost; 45 if ( dist[v]>dist[u]+cost ) 46 { 47 dist[v]=dist[u]+cost; 48 if ( !vis[v] ) 49 { 50 vis[v]=true; 51 que.push(v); 52 if ( ++cnt[v]>n ) return false; 53 } 54 } 55 } 56 } 57 return true; 58 }
1.(UVA247)https://vjudge.net/problem/UVA-247
题意:给定n个人和m组关系(x,y表示x打电话给y,单向),找出所有的环,分别输出每个环内的元素
分析:当vis[x][y]=vis[y][x]=true表示这两个点处于一个环内,利用floyd传递闭包,最后注意输出格式
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<map> 5 #include<string> 6 #include<iostream> 7 #include<vector> 8 using namespace std; 9 const int maxn=30; 10 map<string,int>mp; 11 map<int,string>mp_; 12 bool vis[maxn][maxn]; 13 int belong[maxn]; 14 vector<int>G[maxn]; 15 16 int main() 17 { 18 int n,m,cnt,num,id1,id2,h=0; 19 string s1,s2; 20 while ( scanf("%d%d",&n,&m)!=EOF && (n+m) ) 21 { 22 mp.clear(); 23 mp_.clear(); 24 memset(vis,false,sizeof(vis)); 25 memset(belong,0,sizeof(belong)); 26 for ( int i=1;i<=n;i++ ) 27 { 28 vis[i][i]=true; 29 G[i].clear(); 30 } 31 cnt=0; 32 for ( int i=1;i<=m;i++ ) 33 { 34 cin>>s1>>s2; 35 if ( mp.find(s1)==mp.end() ) mp[s1]=++cnt,mp_[cnt]=s1; 36 id1=mp[s1]; 37 if ( mp.find(s2)==mp.end() ) mp[s2]=++cnt,mp_[cnt]=s2; 38 id2=mp[s2]; 39 vis[id1][id2]=true; 40 } 41 for ( int k=1;k<=n;k++ ) 42 { 43 for ( int i=1;i<=n;i++ ) 44 { 45 for ( int j=1;j<=n;j++ ) 46 { 47 if ( vis[i][k] && vis[k][j] ) vis[i][j]=true; 48 } 49 } 50 } 51 num=0; 52 for ( int i=1;i<=n;i++ ) 53 { 54 if ( belong[i] ) continue; 55 belong[i]=++num; 56 G[num].push_back(i); 57 for ( int j=i+1;j<=n;j++ ) 58 { 59 if ( belong[j] ) continue; 60 if ( vis[i][j] && vis[j][i] ) 61 { 62 belong[j]=belong[i]; 63 G[num].push_back(j); 64 } 65 } 66 } 67 if ( h ) printf("\n"); 68 printf("Calling circles for data set %d:\n",++h); 69 for ( int i=1;i<=num;i++ ) 70 { 71 for ( int j=0;j<G[i].size();j++ ) 72 { 73 cout<<mp_[G[i][j]]; 74 if ( j<G[i].size()-1 ) printf(", "); 75 else printf("\n"); 76 } 77 } 78 } 79 return 0; 80 }
2.(UVA10048)https://vjudge.net/problem/UVA-10048
题意:给定c个点和s条边的有向图,边权代表该路径上的噪音值。每次询问输入两个点,求这两个点间最大噪音值最小的值
分析:Dijkstra算法中每次松弛将本来的dist[v]=dist[u]+cost变成dist[v]=max(dist[u],cost) (在满足条件的前提下)
floyd算法松弛过程同Dijkastra
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=110; 8 const int inf=1e9; 9 struct node{ 10 int v; 11 int c; 12 node(int _v=0,int _c=0):v(_v),c(_c) {} 13 bool operator < (const node &r)const{ 14 return c>r.c; 15 } 16 }; 17 struct Edge{ 18 int v,cost; 19 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 20 }; 21 vector<Edge>E[maxn]; 22 bool vis[maxn]; 23 int dist[maxn][maxn]; 24 int n; 25 26 void addedge(int u,int v,int w) 27 { 28 E[u].push_back(Edge(v,w)); 29 } 30 31 void dij(int s) 32 { 33 memset(vis,false,sizeof(vis)); 34 for ( int i=1;i<=n;i++ ) dist[s][i]=inf; 35 priority_queue<node>que; 36 while ( !que.empty() ) que.pop(); 37 dist[s][s]=0; 38 que.push(node(s,0)); 39 node tmp; 40 while ( !que.empty() ) 41 { 42 tmp=que.top(); 43 que.pop(); 44 int u=tmp.v; 45 if ( vis[u] ) continue; 46 vis[u]=true; 47 for ( int i=0;i<E[u].size();i++ ) 48 { 49 int v=E[u][i].v; 50 int cost=E[u][i].cost; 51 int x=max(cost,dist[s][u]); 52 if ( !vis[v] && dist[s][v]>x ) 53 { 54 dist[s][v]=x; 55 que.push(node(v,dist[s][v])); 56 } 57 } 58 } 59 } 60 61 int main() 62 { 63 int m,q,h=0; 64 while ( scanf("%d%d%d",&n,&m,&q)!=EOF && (n+m+q) ) 65 { 66 for ( int i=1;i<=n;i++ ) 67 { 68 for ( int j=1;j<=n;j++ ) dist[i][j]=inf; 69 dist[i][i]=0; 70 E[i].clear(); 71 } 72 for ( int i=1;i<=m;i++ ) 73 { 74 int u,v,w; 75 scanf("%d%d%d",&u,&v,&w); 76 addedge(u,v,w); 77 addedge(v,u,w); 78 } 79 for ( int i=1;i<=n;i++ ) 80 { 81 dij(i); 82 } 83 if ( h ) printf("\n"); 84 printf("Case #%d\n",++h); 85 while ( q-- ) 86 { 87 int u,v; 88 scanf("%d%d",&u,&v); 89 if ( dist[u][v]==inf ) printf("no path\n"); 90 else printf("%d\n",dist[u][v]); 91 } 92 } 93 return 0; 94 }
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=110; 6 const int inf=1e9; 7 int dist[maxn][maxn]; 8 9 void floyd(int n) 10 { 11 for ( int k=1;k<=n;k++ ) 12 { 13 for ( int i=1;i<=n;i++ ) 14 { 15 for ( int j=1;j<=n;j++ ) 16 { 17 if ( dist[i][k]==inf || dist[k][j]==inf ) continue; 18 if ( dist[i][j]==inf ) dist[i][j]=max(dist[i][k],dist[k][j]); 19 else dist[i][j]=min(dist[i][j],max(dist[i][k],dist[k][j])); 20 } 21 } 22 } 23 } 24 25 int main() 26 { 27 int n,m,q,h=0; 28 while ( scanf("%d%d%d",&n,&m,&q)!=EOF && (n+m+q) ) 29 { 30 for ( int i=1;i<=n;i++ ) 31 { 32 for ( int j=1;j<=n;j++ ) dist[i][j]=inf; 33 dist[i][i]=0; 34 } 35 for ( int i=1;i<=m;i++ ) 36 { 37 int u,v,w; 38 scanf("%d%d%d",&u,&v,&w); 39 dist[u][v]=min(dist[u][v],w); 40 dist[v][u]=min(dist[v][u],w); 41 } 42 floyd(n); 43 if ( h ) printf("\n"); 44 printf("Case #%d\n",++h); 45 while ( q-- ) 46 { 47 int u,v; 48 scanf("%d%d",&u,&v); 49 if ( dist[u][v]==inf ) printf("no path\n"); 50 else printf("%d\n",dist[u][v]); 51 } 52 } 53 return 0; 54 }
3.(UVA658)https://vjudge.net/problem/UVA-658
题意:有一个长度为n的bug,有m个补丁,每个补丁有3个值,分别代表花费的时间,bug在补丁前的状态(“0”代表无所谓,“-”代表bug不存在,“+”代表bug存在),bug在补丁后的状态(“0”代表不变,“+”代表该位置出现bug,“-”代表该位置没有bug),一个补丁可以打多次,求最小的花费时间
分析:将bug转化为二进制形式,0表示该位置有bug,1表示该位置没有bug。所以总共有(1<<n)-1种状态。每次更新时访问所有的补丁(可以等效成“边”) ,若满足条件则转移状态,最后判断(1<<n)-1这个状态
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=2e6+10; 8 const int N=22; 9 const int maxm=110; 10 const int inf=1e9; 11 struct node{ 12 int v; 13 int c; 14 node(int _v=0,int _c=0):v(_v),c(_c) {} 15 bool operator < (const node &r)const{ 16 return c>r.c; 17 } 18 }; 19 bool vis[maxn]; 20 int dist[maxn]; 21 int s; 22 char s1[maxm][N],s2[maxm][N]; 23 int w[maxm],m; 24 25 void dij(int n) 26 { 27 memset(vis,false,sizeof(vis)); 28 for ( int i=0;i<=n;i++ ) dist[i]=inf; 29 priority_queue<node>que; 30 while ( !que.empty() ) que.pop(); 31 dist[s]=0; 32 que.push(node(s,0)); 33 node tmp; 34 while ( !que.empty() ) 35 { 36 tmp=que.top(); 37 que.pop(); 38 int u=tmp.v; 39 if ( vis[u] ) continue; 40 vis[u]=true; 41 for ( int i=1;i<=m;i++ ) 42 { 43 bool flag=true; 44 int len=strlen(s1[i]); 45 for ( int j=0;j<len;j++ ) 46 { 47 if ( s1[i][j]=='0' ) continue; 48 else if ( s1[i][j]=='+' ) 49 { 50 if ( ((1<<j)&u) ) 51 { 52 flag=false; 53 break; 54 } 55 } 56 else if ( s1[i][j]=='-' ) 57 { 58 if ( !((1<<j)&u) ) 59 { 60 flag=false; 61 break; 62 } 63 } 64 } 65 if ( !flag ) continue; 66 int v=u; 67 for ( int j=0;j<len;j++ ) 68 { 69 if ( s2[i][j]=='0' ) continue; 70 else if ( s2[i][j]=='+' ) 71 { 72 if ( ((1<<j)&v) ) v^=(1<<j); 73 } 74 else if ( s2[i][j]=='-' ) 75 { 76 if ( !((1<<j)&v) ) v|=(1<<j); 77 } 78 } 79 int cost=w[i]; 80 if ( !vis[v] && dist[v]>dist[u]+cost ) 81 { 82 dist[v]=dist[u]+cost; 83 que.push(node(v,dist[v])); 84 } 85 } 86 } 87 } 88 89 int main() 90 { 91 int n,h=0,p; 92 while ( scanf("%d%d",&n,&m)!=EOF && (n+m) ) 93 { 94 p=(1<<n)-1; 95 for ( int i=1;i<=m;i++ ) 96 { 97 scanf("%d%s%s",&w[i],s1[i],s2[i]); 98 } 99 s=0; 100 dij(p); 101 printf("Product %d\n",++h); 102 if ( dist[p]!=inf ) printf("Fastest sequence takes %d seconds.\n\n",dist[p]); 103 else printf("Bugs cannot be fixed.\n\n"); 104 } 105 return 0; 106 }
4.(UVA11374)https://vjudge.net/problem/UVA-11374
题意:机场快线分为经济线和商业线,你有一张商业线的车票,可以坐一站商业线,其他时候都只能做经济线,不考虑换乘时间,求一条最快去机场的线路。输入第一行为n,s,e,分别表示点数,起点和终点。下一行一个m表示经济线的线路数,接下来m行有x,y,z表示x-y(双向)花费z分钟。接下来一行一个k表示商业线的线路数,接下来k行x,y,z表示x-y(双向)花费z。输出三行,第一行表示线路,第二行表示换乘商业线的编号,第三行表示时间
分析:首先需要分别以s和e为起点进行两次最短路算法。剩下的只要枚举坐的是哪趟商业线即可,对于任意一条含商业线的路线所花费的时间为d(s,x)+z+d(y,e)与d(s,e)进行比较即可。注意如何打印路径。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=5010; 8 const int maxm=5010; 9 const int inf=1e9; 10 struct node{ 11 int v; 12 int c; 13 node(int _v=0,int _c=0):v(_v),c(_c) {} 14 bool operator < (const node &r)const{ 15 return c>r.c; 16 } 17 }; 18 struct Edge{ 19 int v,cost; 20 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 21 }; 22 vector<Edge>E[maxn]; 23 bool vis[maxn]; 24 int dist[2][maxn]; 25 int pre[2][maxn]; 26 int n; 27 int a[maxm],b[maxm],c[maxm]; 28 29 void addedge(int u,int v,int w) 30 { 31 E[u].push_back(Edge(v,w)); 32 } 33 34 void dij(int s) 35 { 36 memset(vis,false,sizeof(vis)); 37 for ( int i=1;i<=n;i++ ) dist[0][i]=inf; 38 memset(pre[0],-1,sizeof(pre[0])); 39 priority_queue<node>que; 40 while ( !que.empty() ) que.pop(); 41 dist[0][s]=0; 42 que.push(node(s,0)); 43 node tmp; 44 while ( !que.empty() ) 45 { 46 tmp=que.top(); 47 que.pop(); 48 int u=tmp.v; 49 if ( vis[u] ) continue; 50 vis[u]=true; 51 for ( int i=0;i<E[u].size();i++ ) 52 { 53 int v=E[u][i].v; 54 int cost=E[u][i].cost; 55 if ( !vis[v] && dist[0][v]>dist[0][u]+cost ) 56 { 57 dist[0][v]=dist[0][u]+cost; 58 pre[0][v]=u; 59 que.push(node(v,dist[0][v])); 60 } 61 } 62 } 63 } 64 65 void display(int u) 66 { 67 if ( pre[0][u]==-1 ) 68 { 69 printf("%d",u); 70 return; 71 } 72 display(pre[0][u]); 73 printf(" %d",u); 74 } 75 76 int main() 77 { 78 int s,e,k,ans,cnt,m,h=0; 79 while ( scanf("%d%d%d",&n,&s,&e)!=EOF ) 80 { 81 for ( int i=1;i<=n;i++ ) E[i].clear(); 82 scanf("%d",&m); 83 for ( int i=1;i<=m;i++ ) 84 { 85 int u,v,w; 86 scanf("%d%d%d",&u,&v,&w); 87 addedge(u,v,w); 88 addedge(v,u,w); 89 } 90 dij(e); 91 for ( int i=1;i<=n;i++ ) 92 { 93 dist[1][i]=dist[0][i]; 94 pre[1][i]=pre[0][i]; 95 } 96 dij(s); 97 scanf("%d",&k); 98 for ( int i=1;i<=k*2;i+=2 ) 99 { 100 scanf("%d%d%d",&a[i],&b[i],&c[i]); 101 b[i+1]=a[i]; 102 a[i+1]=b[i]; 103 c[i+1]=c[i]; 104 } 105 ans=dist[0][e]; 106 cnt=-1; 107 for ( int i=1;i<=2*k;i++ ) 108 { 109 int num=dist[0][a[i]]+c[i]+dist[1][b[i]]; 110 if ( num<ans ) 111 { 112 ans=num; 113 cnt=i; 114 } 115 } 116 if ( h++>0 ) printf("\n"); 117 if ( cnt==-1 ) 118 { 119 display(e); 120 printf("\n"); 121 printf("Ticket Not Used\n"); 122 } 123 else 124 { 125 display(a[cnt]); 126 for ( int i=b[cnt];i!=e;i=pre[1][i] ) printf(" %d",i); 127 printf(" %d\n",e); 128 printf("%d\n",a[cnt]); 129 } 130 printf("%d\n",ans); 131 } 132 return 0; 133 }
5.(UVA10917)https://vjudge.net/problem/UVA-10917
题意:有n个点和m条双向边,从起点1出发,去往终点2.每次只沿着满足如下条件道路的(A,B)走,存在一条从B出发的路,比所有从A出发回家的路都短。计算一共有多少条路
分析:最短路+dfs,首先用最短路求出所有点到终点2的距离(用来判断某条边是否可走),设dp[i]为从i出发有多少条路可以到达终点,初始化dp[1]=1,其余均为0.然后通过dfs,从1出发。对于点u来说,当边(u,v)满足条件,则dp[u]+=dp[v]
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=1e3+10; 8 const int inf=1e9; 9 struct node{ 10 int v; 11 int c; 12 node(int _v=0,int _c=0):v(_v),c(_c) {} 13 bool operator < (const node &r)const{ 14 return c>r.c; 15 } 16 }; 17 struct Edge{ 18 int v,cost; 19 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 20 }; 21 vector<Edge>E[maxn]; 22 bool vis[maxn]; 23 int dist[maxn],dp[maxn]; 24 int n,s,e; 25 26 void addedge(int u,int v,int w) 27 { 28 E[u].push_back(Edge(v,w)); 29 } 30 31 void dij() 32 { 33 memset(vis,false,sizeof(vis)); 34 for ( int i=1;i<=n;i++ ) dist[i]=inf; 35 priority_queue<node>que; 36 while ( !que.empty() ) que.pop(); 37 dist[s]=0; 38 que.push(node(s,0)); 39 node tmp; 40 while ( !que.empty() ) 41 { 42 tmp=que.top(); 43 que.pop(); 44 int u=tmp.v; 45 if ( vis[u] ) continue; 46 vis[u]=true; 47 for ( int i=0;i<E[u].size();i++ ) 48 { 49 int v=E[u][i].v; 50 int cost=E[u][i].cost; 51 if ( !vis[v] && dist[v]>dist[u]+cost ) 52 { 53 dist[v]=dist[u]+cost; 54 que.push(node(v,dist[v])); 55 } 56 } 57 } 58 } 59 60 int dfs(int u) 61 { 62 vis[u]=true; 63 for ( int i=0;i<E[u].size();i++ ) 64 { 65 int v=E[u][i].v; 66 if ( dist[v]>=dist[u] ) continue; 67 if ( vis[v] ) dp[u]+=dp[v]; 68 else dp[u]+=dfs(v); 69 } 70 return dp[u]; 71 } 72 73 int main() 74 { 75 int m; 76 while ( scanf("%d",&n)!=EOF && n ) 77 { 78 scanf("%d",&m); 79 for ( int i=1;i<=n;i++ ) E[i].clear(); 80 s=2; 81 e=1; 82 for ( int i=1;i<=m;i++ ) 83 { 84 int u,v,w; 85 scanf("%d%d%d",&u,&v,&w); 86 addedge(u,v,w); 87 addedge(v,u,w); 88 } 89 dij(); 90 memset(dp,0,sizeof(dp)); 91 memset(vis,false,sizeof(vis)); 92 dp[s]=1; 93 //vis[e]=true; 94 dfs(e); 95 printf("%d\n",dp[1]); 96 } 97 return 0; 98 }
6.(UVA10537)https://vjudge.net/problem/UVA-10537
题意:运送货物需要缴纳路费,路过一个村庄需要缴纳一个单位的货物,路过城镇每20个货物需要缴纳1个单位的货物(70个需要缴纳4个)。输入时给定一个n表示道路的条数,接下来n行,每行两个字母(大写为城镇,小写为村庄),道路均为双向路。接下来一行包括一个p和两个字母,表示运送的货物数量、起点和终点。输出包括运送货物的最小值和对应线路(若有多条线路,输出字典序最小的)
分析:用最短算法的逆推,设dist[i] 表示进入节点后至少有dist[i]单位的货物才能使达到目的地的货物数量足够,每次选择一个dist[i]最小的未标号结点,更新它所有的前驱,算出所有的dist。假设经过某个城镇后的数量为x,若x%19==0,则y=x/19。若x%19!=0,则y=x/19+1。则y为在该城镇所缴纳的货物
注意:dist数组开longlong,图为无向图,可以直接用字符的阿斯克码当作结点的编号,注意打印路径的写法
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 typedef long long ll; 8 const int maxn=155; 9 const int n=150; 10 const ll inf=1e18; 11 struct node{ 12 int v; 13 ll c; 14 node(int _v=0,ll _c=0):v(_v),c(_c) {} 15 bool operator < (const node &r)const{ 16 return c>r.c; 17 } 18 }; 19 vector<int>E[maxn]; 20 bool vis[maxn]; 21 ll dist[maxn],num; 22 int s,e,pre[maxn]; 23 24 void addedge(int u,int v) 25 { 26 E[u].push_back(v); 27 } 28 29 void dij() 30 { 31 memset(vis,false,sizeof(vis)); 32 memset(pre,-1,sizeof(pre)); 33 for ( int i=0;i<=n;i++ ) dist[i]=inf; 34 priority_queue<node>que; 35 while ( !que.empty() ) que.pop(); 36 dist[s]=num; 37 que.push(node(s,dist[s])); 38 node tmp; 39 while ( !que.empty() ) 40 { 41 tmp=que.top(); 42 que.pop(); 43 int u=tmp.v; 44 if ( vis[u] ) continue; 45 vis[u]=true; 46 for ( int i=0;i<E[u].size();i++ ) 47 { 48 int v=E[u][i]; 49 if ( vis[v] ) continue; 50 ll cost; 51 if ( u>='a' ) cost=1; 52 else 53 { 54 if ( tmp.c%19==0 ) cost=tmp.c/19; 55 else cost=tmp.c/19+1; 56 } 57 if (dist[v]>dist[u]+cost || (dist[v]==dist[u]+cost&&pre[v]>u) ) 58 { 59 pre[v]=u; 60 dist[v]=dist[u]+cost; 61 que.push(node(v,dist[v])); 62 } 63 } 64 } 65 } 66 67 int main() 68 { 69 int m,h=0; 70 char s1[10],s2[10]; 71 while ( scanf("%d",&m)!=EOF && m!=-1 ) 72 { 73 for ( int i=0;i<=n;i++ ) E[i].clear(); 74 for ( int i=1;i<=m;i++ ) 75 { 76 int u,v; 77 scanf("%s%s",s1,s2); 78 u=s1[0]; 79 v=s2[0]; 80 addedge(v,u); 81 addedge(u,v); 82 } 83 scanf("%lld%s%s",&num,s1,s2); 84 e=s1[0]; 85 s=s2[0]; 86 dij(); 87 printf("Case %d:\n%lld\n",++h,dist[e]); 88 while ( e!=s ) 89 { 90 printf("%c-",e); 91 e=pre[e]; 92 } 93 printf("%c\n",s); 94 } 95 return 0; 96 }
7.(UVA11090)https://vjudge.net/problem/UVA-11090
题意:给定一个n个点和m条边的加权有向图,求平均权值最小的回路。
分析:二分+SPFA判负环,首先二分平均值,在进行一次SPFA判断有无负环的存在。在SPFA过程中,因为起初没有起点,所有需要将所有点都存入队列中
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 #include<cmath> 7 using namespace std; 8 const double eps=1e-6; 9 const int maxn=60; 10 const int inf=1e9; 11 struct Edge{ 12 int v; 13 double cost; 14 Edge(int _v=0,double _cost=0):v(_v),cost(_cost) {} 15 }; 16 vector<Edge>E[maxn]; 17 bool vis[maxn]; 18 int cnt[maxn]; 19 double dist[maxn]; 20 int n; 21 22 void addedge(int u,int v,double w) 23 { 24 E[u].push_back(Edge(v,w)); 25 } 26 27 bool spfa(double m) 28 { 29 queue<int>que; 30 while ( !que.empty() ) que.pop(); 31 for ( int i=1;i<=n;i++ ) 32 { 33 dist[i]=0; 34 que.push(i); 35 vis[i]=true; 36 cnt[i]=1; 37 } 38 while ( !que.empty() ) 39 { 40 int u=que.front(); 41 que.pop(); 42 vis[u]=false; 43 for ( int i=0;i<E[u].size();i++ ) 44 { 45 int v=E[u][i].v; 46 double cost=E[u][i].cost-m; 47 if ( dist[v]>dist[u]+cost ) 48 { 49 dist[v]=dist[u]+cost; 50 if ( !vis[v] ) 51 { 52 vis[v]=true; 53 que.push(v); 54 if ( ++cnt[v]>n ) return false; 55 } 56 } 57 } 58 } 59 return true; 60 } 61 62 int main() 63 { 64 int T,m; 65 double l,r,mid; 66 scanf("%d",&T); 67 for ( int h=1;h<=T;h++ ) 68 { 69 scanf("%d%d",&n,&m); 70 for ( int i=1;i<=n;i++ ) E[i].clear(); 71 for ( int i=1;i<=m;i++ ) 72 { 73 int u,v; 74 double w; 75 scanf("%d%d%lf",&u,&v,&w); 76 addedge(u,v,w); 77 } 78 printf("Case #%d: ",h); 79 l=0,r=10000000; 80 while ( r-l>eps ) 81 { 82 mid=(l+r)/2; 83 if ( spfa(mid) ) l=mid; 84 else r=mid; 85 } 86 if ( abs(l-1e7)<eps ) printf("No cycle found.\n"); 87 else printf("%.2lf\n",l); 88 } 89 return 0; 90 }
8.(UVA11478)https://vjudge.net/problem/UVA-11478
题意:给定一个有向图,每条边有一个权值。每次可以选择一个节点u和一个整数d,把所有以u为终点的边的权值减小d,把所有以u为起点的边的权值增加d,最后要让所有边权中的最小值非负且尽量大
分析:注意不同的操作之间互不影响,因此可以按任意顺序实施这些操作。另外对于同一个点的多次操作也可以合并。因此可以设置sum(u)表示所有在结点u上进行的操作。二分答案x,对于边(a,b)来说可以得到sum(b)-sum(a)<=w(a,b) -x,这样就转化为差分约束系统了。当出现负环时表示不存在该答案。判断二分的左右区间,若右边界的答案存在则值无限,若左边界的答案不存在则值不存在
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=510; 8 const int inf=1e4; 9 struct edge{ 10 int v,cost; 11 edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 12 }; 13 vector<edge>E[maxn]; 14 bool vis[maxn]; 15 int cnt[maxn],dist[maxn],s,n; 16 bool flag; 17 18 void addedge(int u,int v,int w) 19 { 20 E[u].push_back(edge(v,w)); 21 } 22 23 bool SPFA(int mid) 24 { 25 memset(vis,false,sizeof(vis)); 26 memset(cnt,0,sizeof(cnt)); 27 for ( int i=0;i<=n;i++ ) dist[i]=inf; 28 vis[s]=true; 29 dist[s]=0; 30 queue<int>que; 31 que.push(s); 32 cnt[s]=1; 33 while ( !que.empty() ) { 34 int u=que.front(); 35 que.pop(); 36 vis[u]=false; 37 for ( int i=0;i<E[u].size();i++ ) { 38 int v=E[u][i].v; 39 int cost; 40 cost=E[u][i].cost-mid; 41 if ( dist[v]>dist[u]+cost ) { 42 dist[v]=dist[u]+cost; 43 if ( !vis[v] ) { 44 vis[v]=true; 45 que.push(v); 46 if ( ++cnt[v]>(n+1) ) return false; 47 } 48 } 49 } 50 } 51 return true; 52 } 53 54 bool judge(int mid) 55 { 56 bool ok=SPFA(mid); 57 if ( ok ) return flag=true; 58 return false; 59 } 60 61 int main() 62 { 63 int m,l,r,mid; 64 while ( scanf("%d%d",&n,&m)!=EOF ) 65 { 66 flag=false; 67 for ( int i=0;i<=n;i++ ) E[i].clear(); 68 s=0; 69 for ( int i=1;i<=n;i++ ) addedge(s,i,0); 70 for ( int i=1;i<=m;i++ ) 71 { 72 int u,v,w; 73 scanf("%d%d%d",&u,&v,&w); 74 addedge(u,v,w); 75 } 76 l=1; 77 r=inf; 78 if ( judge(r) ) printf("Infinite\n"); 79 else if ( !judge(l) ) printf("No Solution\n"); 80 else 81 { 82 while ( r-l>1 ) 83 { 84 mid=(l+r)/2; 85 if ( judge(mid) ) l=mid; 86 else r=mid; 87 } 88 printf("%d\n",l); 89 } 90 } 91 return 0; 92 }
9.(POJ3255)http://poj.org/problem?id=3255
题意:求次短路
分析:次短路模板题
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=1e4+10; 8 const int inf=1e9; 9 struct node{ 10 int v; 11 int c; 12 node(int _v=0,int _c=0):v(_v),c(_c) {} 13 bool operator < (const node &r)const{ 14 return c>r.c; 15 } 16 }; 17 struct Edge{ 18 int v,cost; 19 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 20 }; 21 vector<Edge>E[maxn]; 22 bool vis[maxn]; 23 int dist[2][maxn]; 24 int n,s; 25 26 void addedge(int u,int v,int w) 27 { 28 E[u].push_back(Edge(v,w)); 29 } 30 31 void dij() 32 { 33 for ( int i=1;i<=n;i++ ) 34 { 35 dist[0][i]=inf; 36 dist[1][i]=inf; 37 } 38 priority_queue<node>que; 39 while ( !que.empty() ) que.pop(); 40 dist[0][s]=0; 41 que.push(node(s,0)); 42 node tmp; 43 while ( !que.empty() ) 44 { 45 tmp=que.top(); 46 que.pop(); 47 int u=tmp.v; 48 if ( dist[1][u]<tmp.c ) continue; 49 for ( int i=0;i<E[u].size();i++ ) 50 { 51 int v=E[u][i].v; 52 int cost=E[u][i].cost; 53 int d2=tmp.c+cost; 54 if ( dist[0][v]>d2 ) 55 { 56 swap(dist[0][v],d2); 57 que.push(node(v,dist[0][v])); 58 } 59 if ( dist[1][v]>d2 && dist[0][v]<d2 ) 60 { 61 dist[1][v]=d2; 62 que.push(node(v,dist[1][v])); 63 } 64 } 65 } 66 } 67 68 int main() 69 { 70 int m; 71 while ( scanf("%d%d",&n,&m)!=EOF ) 72 { 73 for ( int i=1;i<=n;i++ ) E[i].clear(); 74 for ( int i=1;i<=m;i++ ) 75 { 76 int u,v,w; 77 scanf("%d%d%d",&u,&v,&w); 78 addedge(u,v,w); 79 addedge(v,u,w); 80 } 81 s=1; 82 dij(); 83 printf("%d\n",dist[1][n]); 84 } 85 return 0; 86 }
10.(luoguP2371)https://www.luogu.org/problemnew/show/P2371
分析:同余最短路。(给定一些数去求一个更大的数是否可能由这些数组成)
首先求出n=min{ai},若x能被凑出,则x+mn也能被凑出。
建n个点(0到n-1),dis[i]分别表示模mn意义下余i的能凑出的数最小为多少。
对于每一个ai,从x向(x+ai)%mn连一条边权为ai的边。
求最短路,则最后求得dis[i],计算一下就可以了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 typedef long long ll; 8 const int maxN=15; 9 const int maxn=5e5+10; 10 const ll inf=1e18; 11 struct node{ 12 int v; 13 ll c; 14 node(int _v=0,ll _c=0):v(_v),c(_c) {} 15 bool operator < (const node &r)const{ 16 return c>r.c; 17 } 18 }; 19 struct Edge{ 20 int v; 21 ll cost; 22 Edge(int _v=0,ll _cost=0):v(_v),cost(_cost) {} 23 }; 24 vector<Edge>E[maxn]; 25 bool vis[maxn]; 26 ll dist[maxn]; 27 int n,s; 28 int a[maxN]; 29 30 void addedge(int u,int v,ll w) 31 { 32 E[u].push_back(Edge(v,w)); 33 } 34 35 void dij() 36 { 37 for ( int i=0;i<n;i++ ) dist[i]=inf,vis[i]=false; 38 priority_queue<node>que; 39 while ( !que.empty() ) que.pop(); 40 dist[s]=0; 41 que.push(node(s,0)); 42 node tmp; 43 while ( !que.empty() ) 44 { 45 tmp=que.top(); 46 que.pop(); 47 int u=tmp.v; 48 if ( vis[u] ) continue; 49 vis[u]=true; 50 for ( int i=0;i<E[u].size();i++ ) 51 { 52 int v=E[u][i].v; 53 if ( vis[v] ) continue; 54 ll cost=E[u][i].cost; 55 if ( dist[v]>dist[u]+cost ) 56 { 57 dist[v]=dist[u]+cost; 58 que.push(node(v,dist[v])); 59 } 60 } 61 } 62 } 63 64 int main() 65 { 66 int N; 67 ll L,R,ans; 68 while ( scanf("%d%lld%lld",&N,&L,&R)!=EOF ) 69 { 70 for ( int i=1;i<=N;i++ ) scanf("%d",&a[i]); 71 sort(a+1,a+1+N); 72 n=a[1]; 73 for ( int i=0;i<n;i++ ) E[i].clear(); 74 s=0; 75 for ( int i=0;i<n;i++ ) 76 { 77 for ( int j=2;j<=N;j++ ) 78 { 79 if ( (a[j]+i)%n!=0 ) addedge(i,(a[j]+i)%n,1ll*a[j]); 80 } 81 } 82 ans=0; 83 dij(); 84 L--; 85 for ( int i=0;i<n;i++ ) 86 { 87 if ( dist[i]<=L ) ans-=(L-dist[i])/n+1; 88 if ( dist[i]<=R ) ans+=(R-dist[i])/n+1; 89 } 90 printf("%lld\n",ans); 91 } 92 return 0; 93 }
11.(luoguP2662)https://www.luogu.org/problemnew/show/P2662
分析:同余最短路,将所有可能出现的长度加入c[]数组,取出最小的作为n,剩余的按照上一题的方式建边。最后的答案应该为ans=max(dist[i]-n),即某一同余类中最大的不能组成数的大小。若ans为初始值0,则不存在最大值,输出-1
注意:最后的答案计算的方式
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=3e3+10; 8 const int inf=1e9; 9 struct node{ 10 int v; 11 int c; 12 node(int _v=0,int _c=0):v(_v),c(_c) {} 13 bool operator < (const node &r)const{ 14 return c>r.c; 15 } 16 }; 17 struct Edge{ 18 int v,cost; 19 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 20 }; 21 vector<Edge>E[maxn]; 22 bool vis[maxn],b[maxn]; 23 int dist[maxn]; 24 int n,s; 25 int a[maxn],c[maxn]; 26 27 void addedge(int u,int v,int w) 28 { 29 E[u].push_back(Edge(v,w)); 30 } 31 32 void dij() 33 { 34 memset(vis,false,sizeof(vis)); 35 for ( int i=0;i<n;i++ ) dist[i]=inf; 36 priority_queue<node>que; 37 while ( !que.empty() ) que.pop(); 38 dist[s]=0; 39 que.push(node(s,0)); 40 node tmp; 41 while ( !que.empty() ) 42 { 43 tmp=que.top(); 44 que.pop(); 45 int u=tmp.v; 46 if ( vis[u] ) continue; 47 vis[u]=true; 48 for ( int i=0;i<E[u].size();i++ ) 49 { 50 int v=E[u][i].v; 51 int cost=E[u][i].cost; 52 if ( !vis[v] && dist[v]>dist[u]+cost ) 53 { 54 dist[v]=dist[u]+cost; 55 que.push(node(v,dist[v])); 56 } 57 } 58 } 59 } 60 61 int main() 62 { 63 int N,M,m,ans; 64 while ( scanf("%d%d",&N,&M)!=EOF ) 65 { 66 memset(b,false,sizeof(b)); 67 for ( int i=1;i<=N;i++ ) 68 { 69 scanf("%d",&a[i]); 70 b[a[i]]=true; 71 for ( int j=a[i]-1;j>=a[i]-M&&j>0;j-- ) b[j]=true; 72 } 73 m=0; 74 for ( int i=1;i<=3000;i++ ) 75 { 76 if ( b[i] ) c[++m]=i; 77 } 78 n=c[1]; 79 for ( int i=0;i<n;i++ ) E[i].clear(); 80 for ( int i=0;i<n;i++ ) 81 { 82 for ( int j=2;j<=m;j++ ) 83 { 84 if ( (i+c[j])%n!=0 ) addedge(i,(i+c[j])%n,c[j]); 85 } 86 } 87 s=0; 88 dij(); 89 ans=0; 90 for ( int i=0;i<n;i++ ) 91 { 92 if ( dist[i]!=inf ) ans=max(ans,dist[i]-n); 93 } 94 if ( ans!=0 ) printf("%d\n",ans); 95 else printf("-1\n"); 96 } 97 return 0; 98 }
12.(HDOJ3873)http://acm.hdu.edu.cn/showproblem.php?pid=3873
题意:有一个n个点和m条边的有向图,起点为1,终点为n,对于第i个点来说会被in[i]个点所保护,只有先到那些保护它的点后才能到该点(可以同时有多支队伍)。求到达终点的最短时间
分析:dij的变形,设置in[i]为保护i的点还有in[i]个,val[i]为到达所有保护点i的点需要的最少的时间.每次访问点u时将它保护的点v进行更新数组in[v]和val[v],当in[v]==0&&dist[v]!=inf时,点v可以入队
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=1e6+10; 8 const int inf=1e9; 9 struct node{ 10 int v; 11 int c; 12 node(int _v=0,int _c=0):v(_v),c(_c) {} 13 bool operator < (const node &r)const{ 14 return c>r.c; 15 } 16 }; 17 struct Edge{ 18 int v,cost; 19 Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 20 }; 21 vector<Edge>E[maxn]; 22 vector<int>G[maxn]; 23 bool vis[maxn]; 24 int dist[maxn],in[maxn],val[maxn]; 25 int n,s; 26 27 void addedge(int u,int v,int w) 28 { 29 E[u].push_back(Edge(v,w)); 30 } 31 32 void dij() 33 { 34 memset(vis,false,sizeof(vis)); 35 for ( int i=1;i<=n;i++ ) dist[i]=inf; 36 priority_queue<node>que; 37 while ( !que.empty() ) que.pop(); 38 dist[s]=0; 39 que.push(node(s,0)); 40 node tmp; 41 while ( !que.empty() ) 42 { 43 tmp=que.top(); 44 que.pop(); 45 int u=tmp.v; 46 if ( vis[u] ) continue; 47 vis[u]=true; 48 for ( int i=0;i<G[u].size();i++ ) 49 { 50 int v=G[u][i]; 51 in[v]--; 52 val[v]=max(val[v],dist[u]); 53 if ( dist[v]!=inf && !in[v] ) 54 { 55 dist[v]=max(dist[v],val[v]); 56 que.push(node(v,dist[v])); 57 } 58 } 59 for ( int i=0;i<E[u].size();i++ ) 60 { 61 int v=E[u][i].v; 62 if ( vis[v] ) continue; 63 int cost=E[u][i].cost; 64 if ( dist[v]>cost+dist[u] ) 65 { 66 dist[v]=cost+dist[u]; 67 if ( !in[v] ) que.push(node(v,dist[v])); 68 } 69 } 70 } 71 } 72 73 int main() 74 { 75 int T,m; 76 scanf("%d",&T); 77 while ( T-- ) 78 { 79 scanf("%d%d",&n,&m); 80 s=1; 81 for ( int i=1;i<=n;i++ ) 82 { 83 E[i].clear(); 84 G[i].clear(); 85 val[i]=0; 86 } 87 for ( int i=1;i<=m;i++ ) 88 { 89 int u,v,w; 90 scanf("%d%d%d",&u,&v,&w); 91 addedge(u,v,w); 92 } 93 for ( int i=1;i<=n;i++ ) 94 { 95 scanf("%d",&in[i]); 96 for ( int j=1;j<=in[i];j++ ) 97 { 98 int x; 99 scanf("%d",&x); 100 G[x].push_back(i); 101 } 102 } 103 dij(); 104 printf("%d\n",dist[n]); 105 } 106 return 0; 107 }
13.(HDOJ4845)http://acm.hdu.edu.cn/showproblem.php?pid=4845
分析:状态压缩+DFS,利用分层思想建立模型,用二进制代表所拿到的钥匙(状态),不同的状态对应不同的图。
设置数组dp[i][j][k]表示从(1,1,0)到(i,j,k)(横坐标为x,纵坐标为y,状态为k)需要的步数,vis[i][j][k]代表有无访问过。key[i][j]代表坐标(i,j)所包含的钥匙状态,从(1,1,0)开始跑BFS即可
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 const int maxn=18; 7 const int maxm=12; 8 const int inf=1e9; 9 struct node{ 10 int x,y,sta; 11 node(int _x=0,int _y=0,int _sta=0):x(_x),y(_y),sta(_sta) {} 12 }; 13 int door[maxn][maxn][maxn][maxn]; 14 int key[maxn][maxn],dp[maxn][maxn][1<<maxm]; 15 bool vis[maxn][maxn][1<<maxm]; 16 int n,m,p,s; 17 int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; 18 19 void BFS() 20 { 21 memset(vis,false,sizeof(vis)); 22 for ( int i=1;i<=n;i++ ) 23 { 24 for ( int j=1;j<=m;j++ ) 25 { 26 for ( int k=0;k<1<<(s+1);k++ ) dp[i][j][k]=inf; 27 } 28 } 29 dp[1][1][0]=0; 30 vis[1][1][0]=0; 31 queue<node>que; 32 que.push(node(1,1,0)); 33 while ( !que.empty() ) 34 { 35 node tmp=que.front(); 36 que.pop(); 37 int x=tmp.x,y=tmp.y,sta=tmp.sta; 38 if ( x==n && y==m ) return; 39 for ( int i=0;i<4;i++ ) 40 { 41 int fx=x+dir[i][0]; 42 int fy=y+dir[i][1]; 43 int h=door[x][y][fx][fy]; 44 int sta_=sta|key[fx][fy]; 45 int t; 46 if ( h!=-1 ) t=sta&(1<<h); 47 if ( h==0 || (h!=-1 && t==0) ) continue; 48 if ( fx<=0 || fx>n || fy<=0 || fy>m || vis[fx][fy][sta_] ) continue; 49 vis[fx][fy][sta_]=true; 50 que.push(node(fx,fy,sta_)); 51 dp[fx][fy][sta_]=dp[x][y][sta]+1; 52 } 53 } 54 return; 55 } 56 57 int main() 58 { 59 int k,ans; 60 while ( scanf("%d%d%d",&n,&m,&p)!=EOF ) 61 { 62 memset(door,-1,sizeof(door)); 63 memset(key,0,sizeof(key)); 64 scanf("%d",&k); 65 for ( int i=1;i<=k;i++ ) 66 { 67 int x1,x2,y1,y2,g; 68 scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&g); 69 door[x1][y1][x2][y2]=door[x2][y2][x1][y1]=g; 70 } 71 scanf("%d",&s); 72 for ( int i=1;i<=s;i++ ) 73 { 74 int x,y,g; 75 scanf("%d%d%d",&x,&y,&g); 76 key[x][y]|=(1<<g); 77 } 78 BFS(); 79 ans=-1; 80 for ( int i=0;i<1<<(s+1);i++ ) 81 { 82 if ( dp[n][m][i]!=inf ) ans=dp[n][m][i]; 83 } 84 if ( ans==inf ) printf("-1\n"); 85 else printf("%d\n",ans); 86 } 87 return 0; 88 }