HDU_Steps6.2 最短路 HDU2544 HDU2112 HDU1385 HDU2923 HDU2722 HDU2377 HDU3191 HDU3399

6.2.1 HDU2544 最短路 裸的dijkstra

6.2.2 HDU2112 HDU Today 数据规模小,map转字符串为数字点,然后dijkstra
6.2.3 HDU1385 Minimum Transport Cost

利用dijk的特性来记录路径,路径相等时比较当前路径和已存路径的字典序

#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <string.h>
#define MAXN 1001
#define INF 1e9
using namespace std;
struct node{
	int v,i;
	node(int a,int b){v=a,i=b;}
	bool operator<(const node& n)const{
		return v>n.v;	
	}		
}; 
int n,map[MAXN][MAXN],done[MAXN],d[MAXN],cost[MAXN],pre[MAXN];
void outpath(int st,int en){
	if(pre[en]!=st)outpath(st,pre[en]);
	printf("-->%d",en);
}
int com(int st,int p1,int p2,int p){
	int l1=2,l2=2,s1[MAXN],s2[MAXN];
	s1[0]=p,s2[0]=p,s1[1]=p1,s2[1]=p2;
	while(p1!=st){s1[l1++]=pre[p1];p1=pre[p1];}
	while(p2!=st){s2[l2++]=pre[p2];p2=pre[p2];}
	/* 这个是对字典序错误的理解 并不是长度优先 
	if(l1>l2)return 0;
	else if(l1<l2)return 1;
	for(int i=l2-1;i>=0;i--){
		if(s1[i]>s2[i])return 0;
		else if(s1[i]<s2[i])return 1;	
	}
	*/
	l1--,l2--;
	while(1){
   		if(s1[l1]>s2[l2]) return 0;
   		else if(s1[l1]<s2[l2]) return 1;
   		l1--,l2--;
   		if(l2<0) return 0;
   		else if(l1<0) return 1;
	}
	
	return 0;
}
void dij(int st,int en){
	if(st==en){
		printf("From %d to %d :\n",st,en);
		printf("Path: %d",st);
		printf("\nTotal cost : 0\n\n");		
		return;	
	}
	priority_queue<node> q;
	memset(done,0,sizeof done);
	memset(pre,-1,sizeof pre);
	for(int i=1;i<=n;i++)d[i]=INF;
	d[st]=0;
	q.push(node(d[st],st));
	while(!q.empty()){
		node nd=q.top();q.pop();
		int u=nd.i;
		if(done[u])continue;
		done[u]=1;
		for(int i=1;i<=n;i++){
			if(d[i]>=d[u]+map[u][i]+cost[i]){
				if(d[i]==d[u]+map[u][i]+cost[i]&&!com(st,u,pre[i],i))continue;
				d[i]=d[u]+map[u][i]+cost[i];
				pre[i]=u;
				q.push(node(d[i],i));	
			}		
		}	
	}
	
	printf("From %d to %d :\n",st,en);
	printf("Path: %d",st);outpath(st,en);printf("\n"); 
	printf("Total cost : %d\n\n",d[en]-cost[en]);
}
int main(){
	while(scanf("%d",&n),n){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				scanf("%d",&map[i][j]);	
				if(map[i][j]==-1)map[i][j]=INF;
			}	
		}
		for(int i=1;i<=n;i++)scanf("%d",&cost[i]);
		 
		int st,en;
		while(scanf("%d%d",&st,&en)){
			if(st==-1&&en==-1)break;
			dij(st,en);			
		}
	}
}

6.2.4 HDU2923 Einbahnstrasse

FLOYD ,注意两点之间可能会有多条路,只记录权值最小的

#include <cstdio>
#include <iostream>
#include <map>
#include <string>
#include <string.h>
using namespace std;
string s,s2,s3,des[1005];
map<string,int> mp;
int n,c,r,ns,maps[105][105];
int main(){
	int cas=1;
	while(cin>>n>>c>>r,n||c||r){
		ns=0;mp.clear();
		
		cin>>s;
		mp[s]=++ns;
		for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)maps[i][j]=1e9;
		
		for(int i=0;i<c;i++){
			cin>>des[i];
			if(mp.count(des[i])==0)mp[des[i]]=++ns;
		}
		for(int i=0;i<r;i++){
			cin>>s>>s2>>s3;
			if(mp.count(s)==0)mp[s]=++ns;
			if(mp.count(s3)==0)mp[s3]=++ns;
			int t1=mp[s],t2=mp[s3];
			int ind=0,dis=0;
			while(s2[ind]<'0'||s2[ind]>'9')ind++;
			while(s2[ind]>='0'&&s2[ind]<='9')dis=dis*10+s2[ind]-'0',ind++;
			//可能会有多条路径,选最短的 
			if(s2[0]=='<'&&dis<maps[t2][t1])maps[t2][t1]=dis;
			if(s2[s2.length()-1]=='>'&&dis<maps[t1][t2])maps[t1][t2]=dis;
		}
		//直接FLOYD 
		for(int k=1;k<=n;k++){
			for(int i=1;i<=n;i++){
				for(int j=1;j<=n;j++){
					if(maps[i][j]>maps[i][k]+maps[k][j])maps[i][j]=maps[i][k]+maps[k][j];	
				}	
			}	
		}
		
		int res=0;
		for(int i=0;i<c;i++)
			res+=maps[1][mp[des[i]]]+maps[mp[des[i]]][1];
		
		printf("%d. %d\n",cas++,res);
	}
} 


6.2.5 HDU2722 Here We Go(relians) Again

建图真的是很麻烦啊,一共(n+1)*(m+1)个点,建图后dijkstra就行了

#include <string.h>
#include <cstdio>
#include <queue>
#define INF 1e9
using namespace std;
struct node{
	int v,i;
	node(int a,int b){v=a,i=b;}
	bool operator <(const node& a)const{return v>a.v;}
};
int n,m,map[500][500];
int done[500],d[500];
int dij(){
	priority_queue<node> q;
	memset(done,0,sizeof done);
	for(int i=1;i<=(n+1)*(m+1);i++)d[i]=INF;
	d[1]=0;
	q.push(node(d[1],1));
	while(!q.empty()){
		node nd=q.top();q.pop();
		int u=nd.i;
		if(done[u])continue;
		done[u]=1;
		for(int i=1;i<=(n+1)*(m+1);i++){
			if(d[i]>d[u]+map[u][i]){
				d[i]=d[u]+map[u][i];	
				q.push(node(d[i],i));
			}
		}
	}
	if(d[(n+1)*(m+1)]==INF)return -1;
	else return d[(n+1)*(m+1)]; 
}
int main(){
	char s[3];int v;
	while(scanf("%d%d",&n,&m),n||m){
		for(int i=1;i<=(n+1)*(m+1);i++)for(int j=1;j<=(n+1)*(m+1);j++)map[i][j]=INF;
		//input 建图很麻烦 一共(n+1)*(m+1)个点 
		int n1,n2;
		for(int i=1;i<=2*n+1;i++){
			if(i%2==1){
				for(int j=1;j<=m;j++){
					n1=(i/2)*(m+1)+j,n2=n1+1;
					scanf("%d%s",&v,s);
					if(v==0)continue;
					if(s[0]=='*')map[n1][n2]=map[n2][n1]=2520/v;
					else if(s[0]=='<')map[n2][n1]=2520/v;
					else if(s[0]=='>')map[n1][n2]=2520/v;	
				}		
			}else{
				for(int j=1;j<=m+1;j++){
					n1=(i/2-1)*(m+1)+j,n2=n1+m+1;
					scanf("%d%s",&v,s);
					if(v==0)continue;
					if(s[0]=='*')map[n1][n2]=map[n2][n1]=2520/v;
					else if(s[0]=='v')map[n1][n2]=2520/v;
					else if(s[0]=='^')map[n2][n1]=2520/v;
				}
			}
		}
		/*
		for(int i=1;i<=(n+1)*(m+1);i++){
			for(int j=1;j<=(n+1)*(m+1);j++){
				printf("%d  ",map[i][j]);
			}	
			printf("\n");
		}
		*/
		
		int r=dij();
		if(r==-1)printf("Holiday\n");
		else printf("%d blips\n",r); 
	}
	return 0;	
}


6.2.6 HDU2377 Bus Pass
看了半天才看懂题目的意思,就是给一张图,然后给一个公交路线。然后在地图中找一个点,使这个点到所有公交路线经过的点的最大距离最小。

从公交路线上的每个点BFS整幅图,就可以得到地图上所有点到这个公交点的距离,记录每个点到公交路线点集的最大距离,即为该点到公交路线的最大值,然后在这些点里选一个值最小的就可以了。

#include <cstdio>
#include <queue>
#include <string.h>
#define INF 1e9
using namespace std;
int cas,nz,nr,mr[21];
int map[10000][11],vis[10000],res[10000],u;
void bfs(int st){
	memset(vis,0,sizeof vis);
	queue<int> q;
	q.push(st);
	vis[st]=1;		
	while(!q.empty()){
		int nu=q.front();q.pop();
		for(int i=1;i<=map[nu][0];i++){
			int t=map[nu][i];
			if(!vis[t]){
				vis[t]=vis[nu]+1;
				q.push(t);	
			}	
		}
	}
	//跟新较大值为当前点到路线点集最远点的最近距离,不能到达点跟新为无穷大 
	for(int i=1;i<=10000;i++){
		if(!vis[i])res[i]=INF;	
		else res[i]=max(res[i],vis[i]);
	}
}
int main(){
	scanf("%d",&cas);
	while(cas--){
		memset(map,0,sizeof map);
		memset(res,0,sizeof res);
		scanf("%d%d",&nr,&nz);
		for(int i=0;i<nr;i++){
			scanf("%d",&u);
			scanf("%d",&map[u][0]);
			for(int j=1;j<=map[u][0];j++)scanf("%d",&map[u][j]); 
		}
		//对每个汽车经过点BFS,找出其它点到它的最短路径	
		for(int i=1;i<=nz;i++){
			scanf("%d",&mr[i]);
			for(int j=1;j<=mr[i];j++){
				scanf("%d",&u);
				bfs(u);
			}
		}
		//找出到点集最远点距离最近的点 
		int r=INF,rind;
		for(int i=1;i<10000;i++){
			if(res[i]<r){
				r=res[i];
				rind=i;
			}
		}
		printf("%d %d\n",r,rind);
	
	}
	return 0;	
} 


6.2.7 HDU3191 How Many Paths Are There 求次短路条数

#include<iostream>
#include<algorithm>
#define N 55
#define M 10000
#define inf 0x7fffffff
using namespace std;
int cnt[N][2],dis[N][2];
bool h[N][2];
int NE,head[N];
int n,m;
struct node{
	int next,v,w;
	node(){};
	node(int a,int b,int c){
		next=a;v=b;w=c;
	}
}E[M];
void init(){
	NE=0;
	memset(head,-1,sizeof(head));
}
void insert(int u,int v,int w){
	E[NE]=node(head[u],v,w);
	head[u]=NE++;
}
void dijkstra(int beg,int end){
	for(int i=0;i<=n;i++){
		dis[i][0]=dis[i][1]=inf;
		cnt[i][0]=cnt[i][1]=0;
	}
	memset(h,0,sizeof(h));
	dis[beg][0]=0;
	cnt[beg][0]=1;
	while(true){
		int u,flag;
		int Min=inf;
		for(int i=0;i<n;i++){
			if(!h[i][0]&&dis[i][0]<Min){
				Min=dis[i][0];
				u=i;flag=0;
			}
			else if(!h[i][1]&&dis[i][1]<Min){
				Min=dis[i][1];
				u=i;flag=1;
			}
		}
		if(u==end&&flag==1) break;
		if(Min==inf) break;
		h[u][flag]=1;
		for(int i=head[u];i!=-1;i=E[i].next){
			int v=E[i].v;
			int w=dis[u][flag]+E[i].w;
			if(dis[v][0]>w){
				if(dis[v][0]!=inf){
					dis[v][1]=dis[v][0];
					cnt[v][1]=cnt[v][0];
				}
				dis[v][0]=w;
				cnt[v][0]=cnt[u][flag];
			}
			else if(dis[v][0]==w)
				cnt[v][0]+=cnt[u][flag];
			else if(dis[v][1]>w){
				dis[v][1]=w;
				cnt[v][1]=cnt[u][flag];
			}
			else if(dis[v][1]==w)
				cnt[v][1]+=cnt[u][flag];
		}
	}
	printf("%d %d\n",dis[end][1],cnt[end][1]);
}
int main(void){
	int s,t;
	while(~scanf("%d%d%d%d",&n,&m,&s,&t)){
		init();
		while(m--){
			int x,y,w;
			scanf("%d%d%d",&x,&y,&w);
			insert(x,y,w);
		}
		dijkstra(s,t);
	}
}


 


6.2.8 HDU3399 In Action DP+Dijkstra

破坏地图上的点,破坏的能量超过一半时系统被破坏

先用最短路求出到地图上每个点的最短路,即为到每个点消耗的最小花费,然后使用DP,01背包,重量为能量,权值为到每个点的花费。然后扫描一遍得到当背包被填充了一半以上时的最小花费和。

#include <cstdio>
#include <string.h>
#include <queue>
#include <algorithm> 
#define MAXN 105
#define INF 1e9
using namespace std;
struct node{
	int v,i;
	node(int a,int b){v=a,i=b;}
	bool operator<(const node& nd)const{return v>nd.v;}	
};
int cas,n,m,u,v,w,tpow;
int map[MAXN][MAXN],pow[MAXN],d[MAXN],done[MAXN],dd[MAXN*MAXN];
void dij(){
	priority_queue<node> q;	
	memset(done,0,sizeof done);
	for(int i=0;i<=n;i++)d[i]=INF;
	d[0]=0;
	q.push(node(d[0],0));

	while(!q.empty()){
		node nd=q.top();q.pop();
		int u=nd.i;
		if(done[u])continue;
		done[u]=1;
		for(int i=0;i<=n;i++){
			if(d[i]>d[u]+map[u][i]){
				d[i]=d[u]+map[u][i];	
				q.push(node(d[i],i));
			}
		}
	}
}
int dp(){
	//DP求最小值 
	for(int i=0;i<=tpow;i++)dd[i]=INF; 
	dd[0]=0;
	for(int i=1;i<=n;i++){
		for(int j=tpow;j>=pow[i];j--){
			dd[j]=min(dd[j],dd[j-pow[i]]+d[i]); 
		}	
	}
	//找出大于一半背包时的最小路径和 
	int res=INF;
	for(int i=tpow/2+1;i<=tpow;i++){
		res=min(res,dd[i]);		
	}
	if(res<INF)return res;
	else return -1;
}
int main(){
	scanf("%d",&cas);
	while(cas--){
		scanf("%d%d",&n,&m);
		
		for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)map[i][j]=INF;			
		tpow=0;
		//Input
		for(int i=0;i<m;i++){
			scanf("%d%d%d",&u,&v,&w);
			if(w<map[u][v])map[u][v]=map[v][u]=w;	
		}
		for(int i=1;i<=n;i++){
			scanf("%d",&pow[i]);
			tpow+=pow[i];
		}
		//求到每点的最短路 
		dij();
		/*
		  转化为DP问题 
		  每个点为物品,路径为权值,能量为重量
		  求装满一半背包的最小权值和 
		*/
		int r=dp();
		if(r==-1)printf("impossible\n");
		else printf("%d\n",r);
		
	}
} 


 

 

你可能感兴趣的:(Algorithm,insert,action,Path,n2,stdstring)