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);
}
}