9021#1259香甜的黄油
题目描述
输入格式
输出格式
样例
数据范围与提示
模板题了。稍微有点背景。
很好过,不多说。
给出点权。边权全部为1。求设在哪个牧场,牛的总移动距离最短。
无论是Floyd还是dijistra,都要有一步假设这个牧场为答案进行计算。不算不知道啊,所以几个牧场,几次计算。
对于Floyd,直接计算;对于dijstra,几个牧场,要跑几次单源最短路径,然后计算。
Floyd
dijstra+堆优化
真是快的一批。。
1 #include <iostream> 2 #include <cstdio> 3 #define R register 4 #define INF 0x7fffffff 5 using namespace std; 6 int ans=INF; 7 int n,p,c,g[810][810],a[510]; 8 inline int ri(){ 9 char c=getchar();int x=0,w=1; 10 while(!isdigit(c)){if(c=='-')w=-1;c=getchar();} 11 while( isdigit(c)){x=(x<<3)+(x<<1)+c-48;c=getchar();} 12 return x*w; 13 } 14 int main(){ 15 int num,x,y; 16 for(R int i=1;i<=800;++i) 17 for(R int j=1;j<=800;++j) 18 g[i][j]=1000000; 19 20 for(R int i=1;i<=800;++i) 21 g[i][i]=0; 22 23 n=ri(),p=ri(),c=ri(); 24 for(R int i=1;i<=n;++i) 25 num=ri(),a[num]++; 26 27 for(R int i=1;i<=c;++i) 28 x=ri(),y=ri(),num=ri(),g[x][y]=g[y][x]=num; 29 30 for(R int k=1;k<=p;++k) 31 for(R int i=1;i<=p;++i) 32 for(R int j=1;j<=p;++j) 33 if(g[i][k]+g[k][j]<g[i][j])g[i][j]=g[i][k]+g[k][j]; 34 for(R int i=1;i<=p;++i){ 35 int tot=0; 36 for(R int j=1;j<=p;++j)tot+=g[i][j]*a[j]; 37 ans=min(ans,tot); 38 } 39 printf("%d",ans); 40 return 0; 41 }
1 #include <iostream> 2 #include <cstdio> 3 #include <queue> 4 #include <vector> 5 #define MN 1000 6 #define R register 7 #define INF 0x7fffffff 8 using namespace std; 9 int n,m,c,d[MN],a[MN]; 10 typedef pair<int ,int> p; 11 struct edge{int to,cost;}; 12 vector <edge> G[MN]; 13 inline int ri(){ 14 char c=getchar();int x=0,w=1; 15 while(!isdigit(c)){if(c=='-')w=-1;c=getchar();} 16 while( isdigit(c)){x=(x<<3)+(x<<1)+c-48;c=getchar();} 17 return x*w; 18 } 19 inline void dijstra(int x){ 20 priority_queue<p,vector<p>,greater<p> >que; 21 fill(d+1,d+m+1,INF); 22 d[x]=0,que.push(p(0,x));//d[i],i 23 while(!que.empty()){ 24 p q=que.top();que.pop(); 25 int v=q.second; 26 if(d[v]<q.first)continue; 27 for(R int i=0;i<G[v].size();++i){ 28 edge e=G[v][i]; 29 if(d[e.to]>d[v]+e.cost){ 30 d[e.to]=d[v]+e.cost; 31 que.push(p(d[e.to],e.to)); 32 } 33 } 34 } 35 } 36 int main(){ 37 int num,x,y,z; 38 n=ri(),m=ri(),c=ri();//奶牛数N,牧场数m,牧场间道路数C 39 for(R int i=1;i<=n;++i)num=ri(),a[num]++; 40 for(R int i=1;i<=c;++i){ 41 x=ri(),y=ri(),z=ri(); 42 edge e={y,z},u={x,z}; 43 G[x].push_back(e); 44 G[y].push_back(u); 45 } 46 int ans=INF; 47 for(R int i=1;i<=m;++i){ 48 int tot=0; 49 dijstra(i); 50 for(R int j=1;j<=m;++j)tot+=a[j]*d[j]; 51 ans=min(ans,tot); 52 } 53 printf("%d",ans); 54 }
9021#1519最短路径
题目描述
输入格式
输出格式
样例
数据范围与提示
这题只比模板多了一步复杂的预处理。emmm稍微复杂的??
同一层的点,距离为0;与之相邻上下两层的点,距离为C。
于是就有一串恶心的edge e,ee,eee,eeee。。。
看着ppt码了个dijkstra(当然略有不同,变量名码风七七八八的,因为肯定不是看着打的...),
以及百度了一个spfa。spfa快...可能我写的丑。
dijkstra:
1 #include <iostream> 2 #include <cstdio> 3 #include <queue> 4 #include <vector> 5 #define R register 6 #define INF 0x7fffff 7 using namespace std; 8 int n,m,c,T,t; 9 int num[100001],d[300111]; 10 struct edge{int to,cost;}; 11 vector<edge> G[300111]; 12 typedef pair<int ,int> p; 13 inline void dijkstra(int x){ 14 priority_queue<p,vector<p>,greater<p> >que; 15 for(R int i=1;i<=n*3+2;++i)d[i]=INF; 16 d[x]=0;que.push(p(0,x)); 17 while(!que.empty()){ 18 p q=que.top();que.pop(); 19 int v=q.second; 20 if(d[v]<q.first)continue; 21 for(R int i=0;i<G[v].size();++i){ 22 edge e=G[v][i]; 23 if(d[e.to]>d[v]+e.cost){ 24 d[e.to]=d[v]+e.cost; 25 que.push(p(d[e.to],e.to)); 26 } 27 } 28 } 29 } 30 inline int ri(){ 31 char c=getchar();int x=0,w=1; 32 while(!isdigit(c)){if(c=='-')w=-1;c=getchar();} 33 while( isdigit(c)){x=(x<<3)+(x<<1)+c-48;c=getchar();} 34 return x*w; 35 } 36 int main(){ 37 T=ri(); 38 for(R int i=1;i<=T;++i){ 39 t++; 40 for(R int i=1;i<=n*3+2;++i)G[i].clear(); 41 n=ri(),m=ri(),c=ri(); 42 for(R int i=1;i<=n;++i)num[i]=ri(); 43 for(R int i=1;i<=n;++i){ 44 int nm=num[i]; 45 edge e={i,c},ee={nm+n+1,0},eee={i,0},eeee={nm+2*n+1,c}; 46 G[nm+n].push_back(e); 47 G[i].push_back(ee); 48 G[nm+2*n+2].push_back(eee); 49 G[i].push_back(eeee); 50 } 51 for(R int i=1;i<=m;++i){ 52 int u,v,w; 53 u=ri(),v=ri(),w=ri(); 54 edge e={v,w},ee={u,w}; 55 G[u].push_back(e); 56 G[v].push_back(ee); 57 } 58 dijkstra(1); 59 printf("Case #%d: ",t); 60 if(d[n]==INF)printf("-1 "); 61 else printf("%d ",d[n]); 62 } 63 return 0; 64 }
spfa:
1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4 #include<queue>
5 #include<cstring>
6 #include<cstdlib>
7 using namespace std;
8 const int inf=2100000000;
9 int ne,n,m,c;
10 int T;
11 bool vis[200004],use[200004];
12 int dis[200004];
13 int pos[200004];
14 int ra[200004];
15 struct data{
16 int von,w,next;
17 }e[4000004];
18 void insert(int u,int v,int w){
19 ++ne;
20 e[ne].w=w;
21 e[ne].von=v;
22 e[ne].next=pos[u];
23 pos[u]=ne;
24 }
25 queue<int>q;
26 void spfa(){
27 int w,u,v,i;
28 while(!q.empty())q.pop();
29 dis[1]=0; vis[1]=true; q.push(1);
30 while(!q.empty()){
31 u=q.front(); q.pop(); vis[u]=false; i=pos[u];
32 while(i!=0){
33 v=e[i].von;
34 w=e[i].w;
35 if(dis[v]>dis[u]+w){
36 dis[v]=dis[u]+w;
37 if(!vis[v]){vis[v]=true; q.push(v);}
38 }
39 i=e[i].next;
40 }
41 }
42 }
43 int main(){
44 scanf("%d",&T);
45 for(int t=1;t<=T;t++){
46 memset(dis,127/3,sizeof(dis));
47 memset(vis,false,sizeof(vis));
48 memset(pos,0,sizeof(pos));
49 memset(use,false,sizeof(use));
50 ne=0;
51 scanf("%d%d%d",&n,&m,&c);
52 for(int i=1;i<=n;i++){scanf("%d",&ra[i]); use[ra[i]]=true;}
53 for(int i=1;i<n;i++){
54 if(use[i+1]&&use[i])
55 insert(n+i+1,n+i,c),
56 insert(n+i,n+i+1,c);
57 }
58 for(int i=1;i<=n;i++){
59 insert(n+ra[i],i,0);
60 if(ra[i]<n)insert(i,n+ra[i]+1,c);
61 if(ra[i]>1)insert(i,n+ra[i]-1,c);
62 }
63 for(int i=1;i<=m;i++){
64 int u,v,w;
65 scanf("%d%d%d",&u,&v,&w);
66 insert(u,v,w);insert(v,u,w);
67 }
68 spfa();
69 if(dis[n]<inf)printf("Case #%d: %d
",t,dis[n]);
70 else printf("Case #%d: %d
",t,-1);
71 }
72 return 0;
73 }
P1875 佳佳的魔法药水
题目背景
发完了 k 张照片,佳佳却得到了一个坏消息:他的 MM 得病了!佳佳和大家一样焦急 万分!治好 MM 的病只有一种办法,那就是传说中的 0 号药水 ……怎么样才能得到 0 号药 水呢?你要知道佳佳的家境也不是很好,成本得足够低才行……
题目描述
得到一种药水有两种方法:可以按照魔法书上的指导自己配置,也可以到魔法商店里去 买——那里对于每种药水都有供应,虽然有可能价格很贵。在魔法书上有很多这样的记载:
1 份 A 药水混合 1 份 B 药水就可以得到 1 份 C 药水。(至于为什么 1+1=1,因为……这是魔 法世界)好了,现在你知道了需要得到某种药水,还知道所有可能涉及到的药水的价格以及 魔法书上所有的配置方法,现在要问的就是:1.最少花多少钱可以配制成功这种珍贵的药水;
2.共有多少种不同的花费最少的方案(两种可行的配置方案如果有任何一个步骤不同则视为 不同的)。假定初始时你手中并没有任何可以用的药水。
输入输出格式
输入格式:
第一行有一个整数 N(N<=1000),表示一共涉及到的药水总数。药水从 0~N1 顺序编号,0 号药水就是 最终要配制的药水。
第二行有 N 个整数,分别表示从 0~N1 顺序编号的所有药水在魔法商店的价格(都表示 1 份的价格)。
第三行开始,每行有 3 个整数 A、B、C,表示 1 份 A 药水混合 1 份 B 药水就可以得到 1 份 C 药水。注意,某两种特定的药水搭配如果能配成新药水的话,那么结果是唯一的。也就是 说不会出现某两行的 A、B 相同但 C 不同的情况。
输入以一个空行结束。
输出格式:
输出两个用空格隔开的整数,分别表示得到 0 号药水的最小花费以及花费最少的方案的个 数。
输入输出样例
说明
样例说明:
最优方案有 3 种,分别是:直接买 0 号药水;买 4 号药水、5 号药水配制成 1 号药水,直接 买 2 号药水,然后配制成 0 号药水;买 4 号药水、5 号药水配制成 1 号药水,买 3 号药水、6 号药水配制成 2,然后配制成 0。
既然把他标上了最短路的标签,那就不难想到以想象成连通图的方式,解决第一问。由于还要记录方案,不选择dijkstra。
spfa:
1 #include <iostream> 2 #include <cstdio> 3 #define R register 4 #define INF 0x7fffff 5 #define MN 1005 6 using namespace std; 7 int n,d[MN],ans[MN],g[MN][MN]; 8 bool vis[MN]; 9 inline int ri(){ 10 char c=getchar();int x=0,w=1; 11 while(!isdigit(c)){if(c=='-')w=-1;c=getchar();} 12 while( isdigit(c)){x=(x<<3)+(x<<1)+c-48;c=getchar();} 13 return x*w; 14 } 15 int main(){ 16 n=ri(); 17 for(R int i=1;i<=n;++i)d[i]=ri(),ans[i]=1; 18 int u,v,w; 19 while(scanf("%d%d%d",&u,&v,&w)==3)g[u+1][v+1]=g[v+1][u+1]=w+1;//+1变成习惯的储存方式 20 for(R int i=1;i<n;++i){ 21 int tmp=INF; 22 for(R int j=1;j<=n;++j)if(!vis[j]&&d[j]<tmp)tmp=d[j],v=j; 23 vis[v]=1; 24 for(R int j=1;j<=n;++j)if(vis[j]&&g[v][j]){ 25 if(d[v]+d[j]==d[g[v][j]])ans[g[v][j]]+=ans[v]*ans[j]; 26 if(d[v]+d[j]<d[g[v][j]])d[g[v][j]]=d[v]+d[j],ans[g[v][j]]=ans[v]*ans[j]; 27 } 28 } 29 printf("%d %d",d[1],ans[1]); 30 return 0; 31 }
P4610 [COCI2011-2012#7] KAMPANJA
题目背景
临近选举,总统要在城市111和城市222举行演讲。他乘汽车完成巡回演讲,从111出发,途中要经过城市222,最后必须回到城市111.特勤局对总统要经过的所有城市监控。为了使得费用最小,必须使得监控的城市最少。求最少要监控的城市。
题目描述
一共有NNN个城市,有MMM条有向边。(0<=N,M<=200)(0<=N,M<=200)(0<=N,M<=200) 有N从1出发途中要经过222,最后要回到1的路线中最少要经过的点的数目。
输入输出格式
输入格式:
第一行包含222个整数N,MN,MN,M。NNN表示城市的数目,MMM表示有向边的数目。 接下来MMM行,每行两个数A,BA,BA,B,表示从AAA到BBB有一条有向边。
输出格式:
最少要监控的城市的数量。
输入输出样例
6 7 1 3 3 4 4 5 5 1 4 2 2 6 6 3
6
说明
0<=N,M<=2000<=N,M<=2000<=N,M<=200
本题数据加强by Imagine