PPOJ刷题-2
Posted Mr.wu123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PPOJ刷题-2相关的知识,希望对你有一定的参考价值。
PPOJ刷题-2
1118: 继续畅通工程(kruskal)
题目描述
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
输入
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。
当N为0时输入结束。
输出
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
样例输入
3
1 2 1 0
1 3 2 0
2 3 4 0
3
1 2 1 0
1 3 2 0
2 3 4 1
3
1 2 1 0
1 3 2 1
2 3 4 1
0
样例输出
3
1
0
#include<bits/stdc++.h>
using namespace std;
const int N=105;
struct Edge
int s,e,len;
edge[N*(N-1)/2];
int n,m,father[N];//分别表示点数,边数,和并查集情况
int findfd(int x)
if(father[x]==x)
return x;
return findfd(father[x]);
int cmp(Edge a,Edge b)//按照边长进行排序
return a.len<b.len;
int Kruskal(int m)
sort(edge+1,edge+m+1,cmp);//对边进行排序
int cost=0;
for(int i=1;i<=m;i++)//边数刚好构成最小生成树
int x=findfd(edge[i].s);
int y=findfd(edge[i].e);
if(x!=y)
father[x]=y;
cost+=edge[i].len;
return cost;
int main()
while(cin>>n&&n)
for(int i=1;i<=n;i++)
father[i]=i;
m=n*(n-1)/2;
for(int i=1;i<=m;i++)
int c,d;
cin>>edge[i].s>>edge[i].e>>c>>d;
if(!d) edge[i].len=c;
else edge[i].len=0;
printf("%d\\n",Kruskal(m));
return 0;
1138: N皇后问题(DFS)
题目描述
在一个N*N的棋盘上,问你有多少不同的方式摆放N个皇后。
每个皇后所处的行、列、两条对角线上都不能有其他皇后。
输入
无需处理到EOF
一个整数N,3<=N<=13
输出
输出不同的方案数
样例输入
4
样例输出
2
#include<bits/stdc++.h>
using namespace std;
int col[32],r[32],l[32];//分别标记行,主对角线和副对角线
int n,ans=0;
void DFS(int row)//每行遍历
if(row==n+1)
ans++;
return;
for(int i=1;i<=n;i++)
if(!col[i]&&!r[i-row+n]&&!l[i+row])//+n是防止数组越界
col[i]=r[i-row+n]=l[i+row]=1;
DFS(row+1);
col[i]=r[i-row+n]=l[i+row]=0;
int main()
cin>>n;
DFS(1);
cout<<ans<<endl;
return 0;
1286: PIPI运货(Floyd)
题目描述
PIPI是一个商人,经常需要将货物从A地运到B地,我们可以把PIPI经常活动的区域抽象成一个n个结点的地图,用一个nxn的矩阵表示。
矩阵第i行第j列的值代表PIPI从 i 地将货物运到 j 地所需要的固定费用,若该值为-1则代表 i 和 j之间没有直接的通路,注意道路是双向的。
除了上述固定费用外,PIPI在经过每一个结点时都需要交一次过路费(起点和终点不需要交过路费)。
作为一个精打细算的商人,你能帮PIPI计算出从A地到B地的最少费用是多少吗?
输入
第一行输入结点数目n (0<n<=100)
接下来n行输入一个nxn的矩阵(矩阵的值不大于1000)。
第n+2行输入n个数,代表每个结点的过路费cost(cost<=1000)。
第n+3行输入一个数q (q<=10000),代表PIPI的询问次数。
接下来q行,每行输入两个数字,询问A到B的最少花费。
输出
输出q个数字,代表q次询问的结果。若询问的两个地点不可达,输出-1.
样例输入
5
0 3 22 -1 4
3 0 5 -1 -1
22 5 0 9 20
-1 -1 9 0 4
4 -1 20 4 0
5 17 8 3 1
3
1 3
3 5
2 4
样例输出
21
16
17
#include<bits/stdc++.h>
using namespace std;
const int INF=1e8;
int R[102][102],C[102];
int main()
int n;
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
int k;
cin>>k;
R[i][j]=(k==-1?INF:k);
for(int j=1;j<=n;j++)
cin>>C[j];
for(int k=1;k<=n;k++)//其中的k表示i->j中所经过的点,如果路径长度小就更新
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(R[i][k]+R[k][j]+C[k]<R[i][j])
R[i][j]=R[i][k]+R[k][j]+C[k];
int m;
cin>>m;
while(m--)
int x,y;
cin>>x>>y;
cout<<R[x][y]<<endl;
return 0;
1304: 盗窃团伙(Floyd)
题目描述
美丽祥和的CSU校园里有许多门面,每个门面都出租给做生意的商户,商户之间都在做着各自的生意。但是在宁静的校园里也会有邪恶势力存在。CSU存在着一个盗窃团伙麓石开,盗窃团伙为首的是鸡腿和xiefang,他们总是想着如何去盗窃所有门面商户的商品,然后疯狂的盗取别人的劳动成果。
现在给定n个门面的路线图,若门面i和门面j有一条直接通路,那么在图里面我们用一条无向边来表示i和j可达,边上的权值是门面i和门面j的道路长度。现在鸡腿和xiefang准备在n个门面中选定一个门面租赁,便于偷窃其他所有门面的商品,所以他们对租赁门面的要求是,距离他们租赁门面最远的门面到该门面的路程最短。试问他们应该租赁哪一个门面。
输入
输入第一行包括两个数字n和m , 分别代表CSU的门面数目和门面之间的路径数目( n<=500 m <=10000)。
接下来m行每行输入三个数字 u v w ,代表门面u和门面v之间的距离是w。(1<=u,v <=n , 1<=w <=1000)
输出
输出他们会租赁的门面和与该门面相距最远门面的距离,若有多个合法门面,则输出编号最小的那一个。若他们无法偷窃所有的门面,输出"What a pity!"
样例输入
3 3
1 2 3
1 3 4
2 3 1
样例输出
2 3
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
int mp[505][505],fa[505],n,m;
int find_F(int x)
if(fa[x]!=x)
fa[x]=find_F(fa[x]);
return fa[x];
void Floyd()
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(mp[i][k]+mp[k][j]<mp[i][j])
mp[i][j]=mp[i][k]+mp[k][j];
void solve()
Floyd();
int center_ans=1,Ans=INF;
for(int center=1;center<=n;center++)//查找一点到某一点的最远的最小距离
int MaxDis=0;
for(int j=1;j<=n;j++)
MaxDis=max(MaxDis,mp[center][j]);
if(Ans>MaxDis)
Ans=min(Ans,MaxDis);
center_ans=center;
printf("%d %d\\n",center_ans,Ans);
int main()
cin>>n>>m;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int j=1;j<=n;j++)
mp[i][j]=(i==j?0:INF);
for(int i=1;i<=m;i++)
int x,y,c;
cin>>x>>y>>c;
mp[x][y]=mp[y][x]=c;
if(find_F(x)!=find_F(y))
fa[x]=fa[y];
int cnt=0;
for(int i=1;i<=n;i++)
if(fa[i]==i) cnt++;
if(cnt>1)
printf("What a pity!\\n");
else
solve();
return 0;
1306: 盗窃团伙II(Kruskal)
题目描述
听说PIPI家又有新产品了,盗窃团伙麓石开的鸡腿和xiefang开始计划着要去PIPI家偷产品了。要是偷到了,他们就可以把PIPI家的产品理不直气也壮的高价售出了!!!
CSU的地下有二战时构建的地下交通网络,交通网络中有n个枢纽,m条隧道,每个隧道都连接了两个交通枢纽。麓石开团伙在 1 号枢纽,而PIPI家的产品中心刚好位于n号枢纽,现在他们准备从地下隧道直通PIPI家的产品中心。但是这些隧道已经年久失修,需要翻新一遍才能够安全通过。现在麓石开想请若干家施工公司将其中的一些隧道翻新,使得他们能够从 1 号枢纽走到 n 号枢纽。这些施工公司能够同时开工翻新隧道,但是每一家公司都只能翻新一条隧道。 (两个枢纽之间可能有多条隧道)
麓石开只想着尽可能早一点的偷到PIPI家的新产品,请问至少需要多少天,他们才能够修通隧道,进入PIPI家的产品中心偷产品??
输入
输入的第一行包含两个整数n, m,用一个空格分隔,分别表示交通枢纽的数量和候选隧道的数量 (n<=1e5 , m<=2e5)。
第2行到第m+1行,每行包含三个整数a, b, c,表示枢纽a和枢纽b之间可以修建一条隧道,需要的时间为c天 (1<=a,b<=n , 0<c<=1e5)。
输出
输出盗窃团伙至少需要多少天才能偷到PIPI家的产品?若PIPI足够幸运,让他们没有办法偷到产品,则输出"How lucky!"
样例输入
6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6
样例输出
6
提示
然鹅PIPI并没有 How lucky 的时候 ,o(╥﹏╥)o
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int fa[N],n,m;
struct edge
int s,e,c;
s[2*N];
int cmp(edge a,edge b)
return a.c<b.c;
int find_f(int x)//压缩版并查集
return fa[x]==x?x:fa[x]=find_f(fa[x]);
int Kruskal()
sort(s,s+m,cmp);
for(int i=0;i<m;i++)
if(find_f(s[i].s)!=find_f(s[i].e))
fa[find_f(s[i].s)]=find_f(s[i].e);
if(find_f(1)==find_f(n))//找到最少修建好1到n所需的时间
return s[i].c;
//因为是从小到大排序,如果1到n所需时间短就会马上输出
//如果所需时间长,在构建最小生成树的过程中就会输出
//不管如何所需最少时间都是此刻所连接了1到n的路径时间
return -1;
int main()
cin>>n>>m;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=0;i<m;i++)
cin>>s[i].s>>s[i].e>>s[i].c;
int ans=Kruskal();
if(ans==-1)
printf("How lucky!\\n");
else
printf("%d\\n",ans);
return 0;
1337: 汉诺塔问题(递归)
题目描述
假设有三个分别命名为A、B和C的塔座,在塔座X上插有n个直径大小各不相同、依小到大编号为1,2,…,n的圆盘。现要求将A轴上的n个圆盘移至塔座C上并仍按同样顺序叠排,圆盘移动时必须遵循下列规则:
1)每次只能移动一个圆盘;
2)圆盘可以插在A、B和C中的任一塔座上;
3)任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。
输入
输入包含多组测试用例。
每组样例输入一个正整数n (n<=15)
输出
对于每组测试样例,输出每一步如何进行移动。
样例输入
1
2
3
样例输出
Move disk 1 from A to C
Move disk 1 from A to B
Move disk 2 from A to C
Move disk 1 from B to C
Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
#include<bits/stdc++.h>
using namespace std;
int n;
void Move(char x,int n,char y)
printf("Move disk %d from %c to %c\\n",n,x,y);
void hanoi(int n,char x,char y, char z)
if(n==1) Move(x,1,z);
else
hanoi(n-1,x,z,y);//先将上面n-1个小盘子从A柱经过C柱放到B柱上
Move(x,n,z);//将最底层的盘子从A柱放到C柱
hanoi(n-1,y,x,z);//将剩下的n-1个盘子从B柱经过A柱放到C柱
int main()
while(cin>>n)
hanoi(n,'A','B','C');
printf("\\n");
return 0;
1273: 三个有序数组的交集
题目描述
现在有三个有序数组 A , B ,C ,请你求出他们的交集。
输入
第一行输入三个正整数 n , m , q 表示三个有序数组的大小 (1<=n,m,q<=1e5)。
第二行输入数组A。
第三行输入数组B。
第四行输入数组C。
输出
输出一行,表示他们的交集,元素之间以空格分割。
样例输入
5 5 5
1 2 3 4 5
1 2 5 7 9
1 3 4 5 8
样例输出
1 5
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int main()
//i、j、k分别为遍历三个数组的指针,x为指向元素的最小值
int i,j,k;
int x,n,m,q;
int A[N],B[N],C[N];
cin>>n>>m>>q;
for(i=0;i<n;i++)
cin>>A[i];
for(i以上是关于PPOJ刷题-2的主要内容,如果未能解决你的问题,请参考以下文章