T1:
题目
无向图 G 有 n 个顶点和 m 条边。求 G 的连通分量的数目。
INPUT
第1行,2个整数n和m,用空格分隔,分别表示顶点数和边数
第2到m+1行,每行两个整数u和v,用空格分隔,表示顶点u到顶点v有一条边,u和v是顶点编号
OUTPUT
1行,1个整数,表示所求连通分量的数目。
Sample
INPUT
6 5
1 3
1 2
2 3
4 5
5 6
OUTPUT
2
Time limit
200ms
Memory limit
10MB
Data range
1≤n≤50000, 1≤m≤100000.1≤u,v≤n.
Solution
并查集,边连接两点如果不在同一块中将二者合并并将答案-1,在同一块中不做任何操作
赛时AC代码
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
int fa[100005],n,m,z,x,y;
void load(){
for(int i=1;i<=n;i++)fa[i]=i;
}
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void hebin(int x,int y){
fa[find(x)]=find(y);
}
int main(){
scanf("%d%d",&n,&m);
load();
int ans = n;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
if(find(x) == find(y))continue;
hebin(x,y);
ans--;
}
printf("%d",ans);
return 0;
}
T2:
题目
整数拆分是一个古老又有趣的问题。请给出将正整数 n 拆分成 k 个正整数的所有不重复方案。例如,将 5 拆分成 2 个正整数的不重复方案,有如下2组:(1,4)和(2,3)。注意(1,4) 和(4,1)被视为同一方案。每种方案按递增序输出,所有方案按方案递增序输出。
INPUT
1行,2个整数n和k,用空格分隔
OUTPUT
若干行,每行一个拆分方案,方案中的数用空格分隔。
最后一行,给出不同拆分方案的总数。
Sample
INPUT
5 2
OUTPUT
1 4
2 3
2
Time limit
100ms
Memory limit
1MB
Data range
1≤k≤n≤50.
Solution
观察到数据范围很小,dfs暴力即可
赛时AC代码
#include <bits/stdc++.h>
using namespace std;
int n,k,ce;
int to[100001],nex[100001],head[100001],val[100001];
int stac[100005],top;
int ans;
int read(){
int x=0,y=1;char ch=getchar();
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')y=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*y;
}
void dfs(int x,int num){
if(num == k && x == 0){
ans++;
for(int i=1;i<=top;i++){
printf("%d",stac[i]);
if(i != top)printf(" ");
}
printf("\n");
return;
}
if(x < stac[top] || num > k)return;
for(int i=stac[top];i<=x;i++){
stac[++top] = i;
dfs(x - i,num + 1);
top--;
}
}
int main(){
n = read(),k = read();
stac[0] = 1;
dfs(n,0);
printf("%d",ans);
return 0;
}
T3:
题目
利用变换规则,一个数可以变换成另一个数。变换规则如下:(1)x 变为x+1;(2)x 变为2x;(3)x 变为 x-1。给定两个数x 和 y,至少经过几步变换能让 x 变换成 y.
INPUT
1行,2个整数x和y,用空格分隔
OUTPUT
第1行,1个整数s,表示变换的最小步数。
第2行,s个数,用空格分隔,表示最少变换时每步变换的结果。规则使用优先级顺序: (1),(2),(3)。
Sample
INPUT
2 14
OUTPUT
4
3 6 7 14
Time limit
100ms
Memory limit
5MB
Data range
1≤x,y≤100000.
Solution
可以转化为图+最短路模型,bfs即可,被优先级卡了很烦,注意优先级
赛后AC代码
#include <bits/stdc++.h>
using namespace std;
int n,k,ce;
int to[450001],nex[450001],head[200001];
bool used[200003];
int dis[200001];
int stac[100001],top;
int ans[100001];
bool flag;
queue<int> q;
int read(){
int x=0,y=1;char ch=getchar();
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')y=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*y;
}
void add(int u,int v){
to[++ce]=v;nex[ce]=head[u];head[u]=ce;
}
void spfa(int s){
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q.push(s);
used[s]=true;
while(!q.empty()){
int u=q.front();q.pop();
used[u]=false;
if(dis[u + 1] == dis[u] + 1){add(u,u + 1);if(!used[u + 1]){q.push(u + 1);used[u + 1] = 1;}}
if(u <= 100000 && dis[u * 2] == dis[u] + 1){add(u,u * 2);if(!used[u * 2]){q.push(u * 2);used[u * 2] = 1;}}
if(u >= 1 && dis[u - 1] == dis[u] + 1){add(u,u - 1);if(!used[u - 1]){q.push(u - 1);used[u - 1] = 1;}}
if(dis[u + 1] > dis[u] + 1){
dis[u + 1] = dis[u] + 1;
add(u,u + 1);
if(!used[u + 1]){
q.push(u + 1);
used[u + 1] = 1;
}
}
if(u <= 100000 && dis[u * 2] > dis[u] + 1){
dis[u * 2] = dis[u] + 1;
add(u,u * 2);
if(!used[u * 2]){
q.push(u * 2);
used[u * 2] = 1;
}
}
if(u >= 1 && dis[u - 1] > dis[u] + 1){
dis[u - 1] = dis[u] + 1;
add(u,u - 1);
if(!used[u - 1]){
q.push(u - 1);
used[u - 1] = 1;
}
}
}
}
void getroad(int x){
if(top > dis[k])return;
if(x == k){
if(!flag){
for(int i=1;i<=top;i++)ans[i] = stac[i];
flag = 1;
} else {
for(int i=1;i<=top;i++){
if(stac[i] - stac[i - 1] == 1 && ans[i] - ans[i - 1] == 1)continue;
if(stac[i] - stac[i - 1] == -1 && ans[i] - ans[i - 1] == -1)continue;
if(stac[i] == 2 * stac[i - 1] && ans[i] == 2 * ans[i - 1])continue;
if(stac[i] - stac[i - 1] == 1){
for(int j=1;j<=top;j++)ans[j] = stac[j];
return;
}
else if(stac[i] == 2 * stac[i - 1] && ans[i] - ans[i - 1] == -1){
for(int j=1;j<=top;j++)ans[j] = stac[j];
return;
}
}
return;
}
return;
}
for(int i=head[x];i;i=nex[i]){
int y = to[i];
if(dis[y] == dis[x] + 1){
stac[++top] = y;
getroad(y);
top--;
}
}
}
int main(){
n = read(),k = read();
if(n > k){
printf("%d\n",n - k);
for(int i=1;i<=n-k;i++){
printf("%d",n - i);
if(i != n - k)printf(" ");
}
return 0;
}
spfa(n);
stac[0] = n;
ans[0] = n;
getroad(n);
printf("%d\n",dis[k]);
for(int i=1;i<=dis[k];i++){
printf("%d",ans[i]);
if(i != dis[k])printf(" ");
}
return 0;
}
//x * 2 + 3
//(x + 1) * 2 + 1
T4:
题目
五一要到了,来一场说走就走的旅行吧。当然,要关注旅行费用。由于从事计算机专业,你很容易就收集到一些城市之间的交通方式及相关费用。将所有城市编号为1到n,你出发的城市编号是s。你想知道,到其它城市的最小费用分别是多少。如果可能,你想途中多旅行一些城市,在最小费用情况下,到各个城市的途中最多能经过多少城市。
INPUT
第1行,3个整数n、m、s,用空格分隔,分别表示城市数、交通方式总数、出发城市编号
第2到m+1行,每行三个整数u、v和w,用空格分隔,表示城市u和城市v的一种双向交通方式费用为w
OUTPUT
第1行,若干个整数Pi,用空格分隔,Pi表示s能到达的城市i的最小费用,1≤i≤n,按城市号递增顺序。
第2行,若干个整数Ci,Ci表示在最小费用情况下,s到城市i的最多经过的城市数,1≤i≤n,按城市号递增顺序。
Sample
INPUT
5 5 1
1 2 2
1 4 5
2 3 4
3 5 7
4 5 8
OUTPUT
0 2 6 5 13
0 1 2 1 3
Time limit
1000ms
Memory limit
10MB
Data range
1≤w≤10000。1≤s≤n≤10000, 1≤m≤100000 。
Solution
SPFA过程中统计经过城市数量取max即可
赛时AC代码
#include <bits/stdc++.h>
using namespace std;
int n,m,s,ce;
int to[200001],nex[200001],head[10001],val[200001];
int used[100003];
int dis[10003];
int mxvis[100003];
queue<int> q;
int read(){
int x=0,y=1;char ch=getchar();
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')y=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*y;
}
void add(int u,int v,int w){
to[++ce]=v;nex[ce]=head[u];head[u]=ce;val[ce]=w;
}
void spfa(int s){
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q.push(s);
used[s]=true;
while(!q.empty()){
int u=q.front();q.pop();
used[u]=false;
for(int i=head[u];i;i=nex[i]){
int v=to[i],w=val[i];
if(dis[u]+w<dis[v]){
mxvis[v] = mxvis[u] + 1;
dis[v]=dis[u]+w;
if(!used[v]){
used[v]=true;
q.push(v);
}
} else if(dis[u] + w == dis[v])
mxvis[v] = max(mxvis[v],mxvis[u] + 1);
}
}
}
int main(){
n = read(),m = read(),s = read();
for(int i=1;i<=m;i++){
int x = read(),y = read(),z = read();
add(x,y,z);
add(y,x,z);
}
spfa(s);
for(int i=1;i<=n;i++){
printf("%d",dis[i]);
if(i != n)printf(" ");
}
printf("\n");
for(int i=1;i<=n;i++){
printf("%d",mxvis[i]);
if(i != n)printf(" ");
}
return 0;
}