连通分量 (100 分)
题目
无向图 G 有 n 个顶点和 m 条边。求 G 的连通分量的数目。
输入格式:
第1行,2个整数n和m,用空格分隔,分别表示顶点数和边数, 1≤n≤50000, 1≤m≤100000.
第2到m+1行,每行两个整数u和v,用空格分隔,表示顶点u到顶点v有一条边,u和v是顶点编号,1≤u,v≤n.
输出格式:
1行,1个整数,表示所求连通分量的数目。
输入样例:
在这里给出一组输入。例如:
6 5
1 3
1 2
2 3
4 5
5 6
输出样例:
在这里给出相应的输出。例如:
2
思路
从头用dfs遍历一遍即可
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
struct edge{
int u,v;
edge(int a,int b){
u=a;
v=b;
}
};
vector<edge> G[N];
int n,vis[N];
void init(){
for(int i=1;i<=n;i++)G[i].clear();
}
void dfs(int u){
vis[u]=1;
//cout<<u<<" ";
for(int i=0;i<G[u].size();i++){
int v=G[u][i].v;
if(!vis[v]){
dfs(v);
}
}
}
int m,u,v;
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>u>>v;
G[u].push_back(edge(u,v));
G[v].push_back(edge(v,u));
}
int sum=0;
for(int i=1;i<=n;i++){
if(!vis[i]){
dfs(i);
sum++;
}
}
cout<<sum<<endl;
return 0;
}
整数拆分 (100 分)
题目
整数拆分是一个古老又有趣的问题。请给出将正整数 n 拆分成 k 个正整数的所有不重复方案。例如,将 5 拆分成 2 个正整数的不重复方案,有如下2组:(1,4)和(2,3)。注意(1,4) 和(4,1)被视为同一方案。每种方案按递增序输出,所有方案按方案递增序输出。
输入格式:
1行,2个整数n和k,用空格分隔, 1≤k≤n≤50.
输出格式:
若干行,每行一个拆分方案,方案中的数用空格分隔。
最后一行,给出不同拆分方案的总数。
输入样例:
在这里给出一组输入。例如:
5 2
输出样例:
在这里给出相应的输出。例如:
1 4
2 3
2
思路
上学期做过的一道题,也是dfs一遍,加上回溯法。
代码
#include<iostream>
#include<algorithm>
using namespace std;
int ntsjjg[100],n,k,ans = 0;
void dfs(int s,int q,int up){
if(q == k && s==0){
ans++;
for(int i = 1; i <= k; ++i){
printf("%d", ntsjjg[i]);
if(i!= k) printf(" ");
else printf("\n");
}
}
for(int i = up;i<=s;++i){
ntsjjg[q+1] = i;
dfs(s-i,q+1,i);
}
}
int main(){
cin>>n>>k;
if(k>n){
printf("0");
return 0;
}
if(k==1){
cout<<n<<endl;
cout<<1<<endl;
return 0;
}
dfs(n,0,1);
printf("%d",ans);
printf("\n");
return 0;
}
数字变换 (100 分)
题目
利用变换规则,一个数可以变换成另一个数。变换规则如下:(1)x 变为x+1;(2)x 变为2x;(3)x 变为 x-1。给定两个数x 和 y,至少经过几步变换能让 x 变换成 y.
输入格式:
1行,2个整数x和y,用空格分隔, 1≤x,y≤100000.
输出格式:
第1行,1个整数s,表示变换的最小步数。
第2行,s个数,用空格分隔,表示最少变换时每步变换的结果。规则使用优先级顺序: (1),(2),(3)。
输入样例:
在这里给出一组输入。例如:
2 14
输出样例:
在这里给出相应的输出。例如:
4
3 6 7 14
思路
可以理解为找最短路的算法。
代码
#include<bits/stdc++.h>
using namespace std;
int rake(int u,int t);
int ro;
int x,y;
struct vp{
int temp,t_emp;
vp(int a,int b):temp(a),t_emp(b){}
};
int visit[200010];
int road[200010];
void bfs(){
queue<vp>q;
q.push(vp(x,0));
visit[x]=1;
while(!q.empty()){
vp c=q.front();
q.pop();
if(c.temp==y){
ro=c.t_emp;
return ;
}
for(int i=1;i<=3;i++){
int z=rake(c.temp,i);
if(z<200000&&!visit[z]){
visit[z]=1;
road[z]=c.temp;
q.push(vp(z,c.t_emp+1));
}
}
}
}
int main(){
cin>>x>>y;
memset(road,-1,sizeof(road));
bfs();
int ok=road[y];
stack<int> ans;
ans.push(y);
while(ok!=-1){
ans.push(ok);
ok=road[ok];
}
if(!ans.empty()) ans.pop();
cout<<ro<<endl;
while(!ans.empty()){
cout<<ans.top();
if(ans.size()!=1)
cout<<" ";
else cout<<endl;
ans.pop();
}
}
int rake(int u,int t){
if(t==1){
return u+1;
}
else if(t==2){
return u*2;
}
else return u-1;
}
旅行 I (100 分)
题目
五一要到了,来一场说走就走的旅行吧。当然,要关注旅行费用。由于从事计算机专业,你很容易就收集到一些城市之间的交通方式及相关费用。将所有城市编号为1到n,你出发的城市编号是s。你想知道,到其它城市的最小费用分别是多少。如果可能,你想途中多旅行一些城市,在最小费用情况下,到各个城市的途中最多能经过多少城市。
输入格式:
第1行,3个整数n、m、s,用空格分隔,分别表示城市数、交通方式总数、出发城市编号, 1≤s≤n≤10000, 1≤m≤100000 。
第2到m+1行,每行三个整数u、v和w,用空格分隔,表示城市u和城市v的一种双向交通方式费用为w , 1≤w≤10000。
输出格式:
第1行,若干个整数Pi,用空格分隔,Pi表示s能到达的城市i的最小费用,1≤i≤n,按城市号递增顺序。
第2行,若干个整数Ci,Ci表示在最小费用情况下,s到城市i的最多经过的城市数,1≤i≤n,按城市号递增顺序。
输入样例:
在这里给出一组输入。例如:
5 5 1
1 2 2
1 4 5
2 3 4
3 5 7
4 5 8
输出样例:
在这里给出相应的输出。例如:
0 2 6 5 13
0 1 2 1 3
思路
dijkstra 加 限制条件
代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int Data[10001];
vector<pair<int,int> >v[10001];
int n;
int m;
void BuildGraph()
{
for(int i=1;i<=n;i++)
Data[i]=1;
int _u,_v,cost_uv;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&_u,&_v,&cost_uv);
v[_u].push_back(make_pair(_v,cost_uv));
v[_v].push_back(make_pair(_u,cost_uv));
}
}
#define MaxCost 1e5;
int CSum[10001];
int PrePath[10001];
int SumPos[10001]={0};
void Dijkstra(int begin)
{
priority_queue<pair<int,int> > q;
for(int i=1;i<=n;i++)
{
CSum[i]=MaxCost;
PrePath[i]=-1;
}
CSum[begin]=0;
q.push(make_pair(0,begin));
while(!q.empty())
{
int NextIndex=q.top().second;
q.pop();
for(vector<pair<int,int> >::iterator it=v[NextIndex].begin();it!=v[NextIndex].end();it++)
if(CSum[it->first]>CSum[NextIndex]+it->second)
{
CSum[it->first]=CSum[NextIndex]+it->second;
SumPos[it->first]=SumPos[NextIndex]+1;
q.push(make_pair(CSum[it->first],it->first));
}
else if(CSum[it->first]==CSum[NextIndex]+it->second)
{
if(SumPos[it->first]<SumPos[NextIndex]+1)
{
//cout<<"SumPos["<<it->first<<"]=SumPos["<<NextIndex<<"]+1="<<SumPos[NextIndex]+1<<endl;
SumPos[it->first]=SumPos[NextIndex]+1;
}
}
}
}
int main()
{
int begin;
scanf("%d %d %d",&n,&m,&begin);
BuildGraph();
Dijkstra(begin);
printf("%d",CSum[1]);
for(int i=2;i<=n;i++)
{
printf(" %d",CSum[i]);
}
printf("\n%d",SumPos[1]);
for(int i=2;i<=n;i++)
{
printf(" %d",SumPos[i]);
}
}