7-1 邻接矩阵表示法创建无向图

采用邻接矩阵表示法创建无向图G ,依次输出各顶点的度。

输入格式:

输入第一行中给出2个整数i(0<i≤10),j(j≥0),分别为图G的顶点数和边数。
输入第二行为顶点的信息,每个顶点只能用一个字符表示。
依次输入j行,每行输入一条边依附的顶点。

输出格式:

依次输出各顶点的度,行末没有最后的空格。

输入样例:

5 7
ABCDE
AB
AD
BC
BE
CD
CE
DE

输出样例:

2 3 3 3 3
#include <bits/stdc++.h>
#define N 2000
using namespace std;
int a[N][N]= {0};//用int型标记图
int n,m;
int serch(int x)
{int cnt=0;int i;for(i=0; i<n; i++)//通过对节点的遍历来计算度的大小{if(a[x][i])cnt++;}return cnt;
}
int main()
{map<char,int>h;//利用map一一对应的特点,将char型顶点用int型数值标记cin>>n>>m;int i;char x;for(i=0; i<n; i++){cin>>x;h[x]=i;}char u,v;for(i=0; i<m; i++){cin>>u>>v;a[h[u]][h[v]]=1;//标记的关键代码a[h[v]][h[u]]=1;}for(i=0; i<n; i++){if(i==0)cout<<serch(i);else cout<<" "<<serch(i);}cout<<endl;return 0;
}

 一.Map概述
Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。
下面举例说明什么是一对一的数据映射。比如一个班级中,每个学生的学号跟他的姓名就存在着一一映射的关系,这个模型用map可能轻易描述,很明显学号用int描述,姓名用字符串描述(本篇文章中不用char *来描述字符串,而是采用STL中string来描述),下面给出map描述代码:
Map<int, string> mapStudent;

7-2 邻接表创建无向图

采用邻接表创建无向图G ,依次输出各顶点的度。

输入格式:

输入第一行中给出2个整数i(0<i≤10),j(j≥0),分别为图G的顶点数和边数。
输入第二行为顶点的信息,每个顶点只能用一个字符表示。
依次输入j行,每行输入一条边依附的顶点。

输出格式:

依次输出各顶点的度,行末没有最后的空格。

输入样例:

5 7
ABCDE
AB
AD
BC
BE
CD
CE
DE

输出样例:

2 3 3 3 3
#include <bits/stdc++.h>using namespace std;
#define N 2000
vector <int>g[N];
map<char,int> h;
int n,m;
int main()
{cin>>n>>m;string s;cin>>s;int i;for(i=0; i<n; i++){h[s[i]]=i;}char u,v;for(i=0; i<m; i++){cin>>u>>v;g[h[u]].push_back(h[v]);g[h[v]].push_back(h[u]);}for(i=0; i<n; i++){if(i==0)cout<<g[h[s[i]]].size();else cout<<" "<<g[h[s[i]]].size();}return 0;
}

7-3 图深度优先遍历

编写程序对给定的有向图(不一定连通)进行深度优先遍历,图中包含n个顶点,编号为0至n-1。本题限定在深度优先遍历过程中,如果同时出现多个待访问的顶点,则优先选择编号最小的一个进行访问,以顶点0为遍历起点。

输入格式:

输入第一行为两个整数n和e,分别表示图的顶点数和边数,其中n不超过20000,e不超过50。接下来e行表示每条边的信息,每行为两个整数a、b,表示该边的端点编号,但各边并非按端点编号顺序排列。

输出格式:

输出为一行整数,每个整数后一个空格,即该有向图的深度优先遍历结点序列。

输入样例1:

3 3
0 1
1 2
0 2

输出样例1:

0 1 2

输入样例2:

4 4
0 2
0 1
1 2
3 0

输出样例2:

0 1 2 3 
#include <bits/stdc++.h>
#define N 40000
using namespace std;vector <int> g[N];//此题的数据量超过了5000所以不能用矩阵来存图
bool vis[N];
void dfs(int x)
{cout<<x<<" ";vis[x]=1;//如果该点被访问过就标记一下,防止环状图的死循环int len=g[x].size();int i;for(i=0; i<len; i++){if(!vis[g[x][i]])dfs(g[x][i]);}
}
int n,m;
int main()
{cin>>n>>m;int v,u;int i;for(i=0; i<m; i++){cin>>u>>v;g[u].push_back(v);//此题为有向图}for(i=0; i<n; i++){sort(g[i].begin(),g[i].end());//题目要求先访问编号小的,所以要先排序}for(i=0; i<n; i++){if(!vis[i])dfs(i);}return 0;
}

7-4 单源最短路径

请编写程序求给定正权有向图的单源最短路径长度。图中包含n个顶点,编号为0至n-1,以顶点0作为源点。

输入格式:

输入第一行为两个正整数n和e,分别表示图的顶点数和边数,其中n不超过20000,e不超过1000。接下来e行表示每条边的信息,每行为3个非负整数a、b、c,其中a和b表示该边的端点编号,c表示权值。各边并非按端点编号顺序排列。

输出格式:

输出为一行整数,为按顶点编号顺序排列的源点0到各顶点的最短路径长度(不含源点到源点),每个整数后一个空格。如源点到某顶点无最短路径,则不输出该条路径长度。

输入样例:

4 4
0 1 1
0 3 1
1 3 1
2 0 1

输出样例:

1 1 
#include <bits/stdc++.h>
#include<queue>
#define N 40000
using namespace std;
int dist[N]= {0x3f3f3f3f};
int head[N],cnt;//cnt 为边的编号
bool vis[N];
typedef pair <int,int> pII;
struct node
{int v,w,next;
};
node e[N];
void add(int u,int v,int w)
{e[cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt++;
}
priority_queue<pII,vector<pII>,greater<pII> > q;
void dij(int st)
{memset(dist,0x3f,sizeof dist);dist[st]=0;q.push(make_pair(0,st));while(!q.empty()){pII tmp=q.top();q.pop();int d=tmp.first,k=tmp.second;if(vis[k])continue;vis[k]=1;for(int j=head[k]; j!=-1; j=e[j].next){int v=e[j].v;if(dist[v]>d+e[j].w){dist[v]=d+e[j].w;q.push(make_pair(dist[v],v));}}}
}
int n,m,s;
int main()
{cin>>n>>m;//源点输入memset(head,-1,sizeof head);//重要!!int u,v,w;int i;for(i=0; i<m; i++){cin>>u>>v>>w;add(u,v,w);//add(v,u,w); 若加上该语句则存的是无向图;但此题要求为有向图}dij(s);for(i=1;i<=n; i++){if(dist[i]<0x3f3f3f3f)cout<<dist[i]<<" ";else ;}return 0;
}

vector存储:

#include <bits/stdc++.h>using namespace std;
#define N 30000
typedef pair<int,int> pII;
vector <pII> g[N];
int dis[N];
bool vis[N];
priority_queue<pII,vector<pII>,greater<pII> >q;
void dij(int s)
{memset(dis,0x3f3f3f3f,sizeof dis);dis[s]=0;q.push({0,s});//{该点到源点的距离,点的编号} 一定要距离在前!因为优先队列按距离来排序while(q.size()){pII t=q.top();q.pop();int d=t.first;int k=t.second;if(vis[k])continue;vis[k]=1;for(int j=0; j<g[k].size(); j++){pII x=g[k][j];if(dis[x.first]>d+x.second){dis[x.first]=d+x.second;q.push({dis[x.first],x.first});}}}
}
int main()
{int n,m;cin>>n>>m;int s=0;int u,v,w;for(int i=0; i<m; i++){cin>>u>>v>>w;g[u].push_back({v,w});//{与u相连的点,该边的边权}}dij(s);for(int i=1; i<n; i++){if(dis[i]<0x3ff3f3f)cout<<dis[i]<<" ";else ;}return 0;
}

sizeof有三种语法形式:

1、sizeof(object); //sizeof(对象);

2、sizeof(type_name); //sizeof(类型);

3、sizeof object; //sizeof 对象;

7-5 列出连通集

给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。

输入格式:

输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。

输出格式:

按照"{ v1​ v2​ ... vk​ }"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。

输入样例:

8 6
0 7
0 1
2 0
4 1
2 4
3 5

输出样例:

{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }
#include <bits/stdc++.h>using namespace std;
int g[20][20];
bool vis[20];
int n,m;
void dfs(int u)
{cout<<u<<" ";vis[u]=1;for(int i=0; i<n; i++){if(!vis[i]&&g[u][i])dfs(i);}
}
void bfs(int u)
{queue<int>q;q.push(u);vis[u]=1;while(!q.empty()){int now=q.front();cout<<now<<" ";q.pop();for(int i=0; i<n; i++){if(!vis[i]&&g[now][i]){q.push(i);vis[i]=1;}}}
}
int main()
{cin>>n>>m;int i;for(i=0; i<m; i++){int u,v;cin>>u>>v;g[u][v]=g[v][u]=1;}for(i=0; i<n; i++){if(!vis[i]){cout<<"{ ";dfs(i);cout<<"}"<<endl;}}memset(vis,0,sizeof vis);for(i=0; i<n; i++){if(!vis[i]){cout<<"{ ";bfs(i);cout<<"}"<<endl;}}return 0;
}

7-6 哈利·波特的考试

哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是haha,将老鼠变成鱼的魔咒是hehe等等。反方向变化的魔咒就是简单地将原来的魔咒倒过来念,例如ahah可以将老鼠变成猫。另外,如果想把猫变成鱼,可以通过念一个直接魔咒lalala,也可以将猫变老鼠、老鼠变鱼的魔咒连起来念:hahahehe。

现在哈利·波特的手里有一本教材,里面列出了所有的变形魔咒和能变的动物。老师允许他自己带一只动物去考场,要考察他把这只动物变成任意一只指定动物的本事。于是他来问你:带什么动物去可以让最难变的那种动物(即该动物变为哈利·波特自己带去的动物所需要的魔咒最长)需要的魔咒最短?例如:如果只有猫、鼠、鱼,则显然哈利·波特应该带鼠去,因为鼠变成另外两种动物都只需要念4个字符;而如果带猫去,则至少需要念6个字符才能把猫变成鱼;同理,带鱼去也不是最好的选择。

输入格式:

输入说明:输入第1行给出两个正整数N (≤100)和M,其中N是考试涉及的动物总数,M是用于直接变形的魔咒条数。为简单起见,我们将动物按1~N编号。随后M行,每行给出了3个正整数,分别是两种动物的编号、以及它们之间变形需要的魔咒的长度(≤100),数字之间用空格分隔。

输出格式:

输出哈利·波特应该带去考场的动物的编号、以及最长的变形魔咒的长度,中间以空格分隔。如果只带1只动物是不可能完成所有变形要求的,则输出0。如果有若干只动物都可以备选,则输出编号最小的那只。

输入样例:

6 11
3 4 70
1 2 1
5 4 50
2 6 50
5 6 60
1 3 70
4 6 60
3 6 80
5 1 100
2 4 60
5 2 80

输出样例:

4 70
#include <bits/stdc++.h>using namespace std;
#define INF 0x3f3f3f3f
int e[110][110];
int n,m;
void floyd()
{for(int k=1; k<=n; k++){for(int i=1; i<=n; i++){for(int j=1; j<=n; j++){e[i][j]=min(e[i][j],e[i][k]+e[k][j]);}}}
}
int main()
{cin>>n>>m;int i;for(i=1; i<=n; i++){for(int j=1; j<=n; j++){if(i==j)e[i][j]=0;else e[i][j]=INF;}}for(i=1; i<=m; i++){int u,v,w;cin>>u>>v>>w;e[u][v]=e[v][u]=w;}floyd();int mi=INF,id=0;for(i=1; i<=n; i++){int mx=0,j;for(j=1; j<=n; j++){if(i!=j){mx=max(mx,e[i][j]);}}if(mx<mi){mi=mx;id=i;}}if(id)cout<<id<<" "<<mi;else cout<<0;return 0;
}

7-7 家庭房产

给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。

输入格式:

输入第一行给出一个正整数N(≤1000),随后N行,每行按下列格式给出一个人的房产:

编号 父 母 k 孩子1 ... 孩子k 房产套数 总面积

其中编号是每个人独有的一个4位数的编号;分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1);k(0≤k≤5)是该人的子女的个数;孩子i是其子女的编号。

输出格式:

首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:

家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积

其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。

输入样例:

10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100

输出样例:

3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000
#include<bits/stdc++.h>
using namespace std;
const int M = 10010;struct node{int number,id;double pparea,ppcnt;
}f[M];int p[M],sz[M],mi[M]    ,cnt[M],ar[M];
bool vis[M];
int find(int x)
{if(x != p[x]) p[x] = find(p[x]);return p[x];
}
bool cmp(struct node x,struct node y)
{if(x.pparea == y.pparea) return x.id < y.id;else return x.pparea > y.pparea;
}
void combin(int x,int y)
{int a = find(x),b = find(y);if(a != b){p[a] = b;sz[b] += sz[a];cnt[b] += cnt[a];ar[b] += ar[a];mi[b] = min(mi[a],mi[b]);}
}
int main()
{int n;cin >> n;for(int i = 0 ; i <M ; i ++ ){p[i] = i;mi[i] = i;sz[i] = 1;}for(int i = 0 ; i < n ; i ++ ){int id,fa,ma,k;cin >> id >> fa >> ma >> k;vis[id] = 1;if(fa != -1){combin(id,fa);vis[fa] = 1;}if(ma != -1){combin(id,ma);vis[ma] = 1;}for(int j = 0 ; j < k ; j ++ ){int son;cin >> son;vis[son] = 1;combin(id,son);}int Cnt,Ar;cin >> Cnt >> Ar;int now;now = find(id);cnt[now] += Cnt;ar[now] += Ar;}int res = 0;for(int i = 0 ; i <M; i ++ ){if(vis[i] && p[i] == i){f[++res].id = mi[i];f[res].number = sz[i];f[res].ppcnt = (double)cnt[i] / sz[i];f[res].pparea = (double)ar[i] / sz[i];}}sort(f+1,f+1+res,cmp);cout << res << endl;for(int i = 1 ; i <= res ; i ++){printf("%04d %d %.3lf %.3lf\n",f[i].id,f[i].number,f[i].ppcnt,f[i].pparea);}}

7-8 森森美图

森森最近想让自己的朋友圈熠熠生辉,所以他决定自己写个美化照片的软件,并起名为森森美图。众所周知,在合照中美化自己的面部而不美化合照者的面部是让自己占据朋友圈高点的绝好方法,因此森森美图里当然得有这个功能。 这个功能的第一步是将自己的面部选中。森森首先计算出了一个图像中所有像素点与周围点的相似程度的分数,分数越低表示某个像素点越“像”一个轮廓边缘上的点。 森森认为,任意连续像素点的得分之和越低,表示它们组成的曲线和轮廓边缘的重合程度越高。为了选择出一个完整的面部,森森决定让用户选择面部上的两个像素点A和B,则连接这两个点的直线就将图像分为两部分,然后在这两部分中分别寻找一条从A到B且与轮廓重合程度最高的曲线,就可以拼出用户的面部了。 然而森森计算出来得分矩阵后,突然发现自己不知道怎么找到这两条曲线了,你能帮森森当上朋友圈的小王子吗?

为了解题方便,我们做出以下补充说明:

  • 图像的左上角是坐标原点(0,0),我们假设所有像素按矩阵格式排列,其坐标均为非负整数(即横轴向右为正,纵轴向下为正)。
  • 忽略正好位于连接A和B的直线(注意不是线段)上的像素点,即不认为这部分像素点在任何一个划分部分上,因此曲线也不能经过这部分像素点。
  • 曲线是八连通的(即任一像素点可与其周围的8个像素连通),但为了计算准确,某像素连接对角相邻的斜向像素时,得分额外增加两个像素分数和的2​倍减一。例如样例中,经过坐标为(3,1)和(4,2)的两个像素点的曲线,其得分应该是这两个像素点的分数和(2+2),再加上额外的(2+2)乘以(2​−1),即约为5.66。

输入格式:

输入在第一行给出两个正整数N和M(5≤N,M≤100),表示像素得分矩阵的行数和列数。

接下来N行,每行M个不大于1000的非负整数,即为像素点的分值。

最后一行给出用户选择的起始和结束像素点的坐标(Xstart​,Ystart​)和(Xend​,Yend​)。4个整数用空格分隔。

输出格式:

在一行中输出划分图片后找到的轮廓曲线的得分和,保留小数点后两位。注意起点和终点的得分不要重复计算。

输入样例:

6 6
9 0 1 9 9 9
9 9 1 2 2 9
9 9 2 0 2 9
9 9 1 1 2 9
9 9 3 3 1 1
9 9 9 9 9 9
2 1 5 4

输出样例:

27.04
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const double r = sqrt(2) - 1;
int flag;
int n,m,sx,sy,ex,ey;
int dir[8][2] = {0,1,1,0,0,-1,-1,0,1,1,-1,-1,-1,1,1,-1};
double rr[8] = {0,0,0,0,r,r,r,r};
double mp[100][100];
double mpm[100][100];
struct po {int x,y;double sum;po(){}po(int x,int y,double sum) {this -> x = x;this -> y = y;this -> sum = sum;}
}temp;
int check(int x,int y) {if(x == ex && y == ey) return flag;int d = (sx - x) * (ey - y) - (sy - y) * (ex - x);if(d) return d / abs(d);return 0;
}
double bfs() {queue<po> q;q.push(po(sx,sy,mp[sx][sy]));mpm[sx][sy] = mp[sx][sy];mpm[ex][ey] = inf;while(!q.empty()) {temp = q.front();q.pop();for(int i = 0;i < 8;i ++) {int tx = temp.x + dir[i][0];int ty = temp.y + dir[i][1];if(tx < 0 || ty < 0 || tx >= n || ty >= m || check(tx,ty) != flag) continue;double sum = temp.sum + mp[tx][ty] + rr[i] * (mp[tx][ty] + mp[temp.x][temp.y]);if(sum < mpm[tx][ty]) {q.push(po(tx,ty,sum));mpm[tx][ty] = sum;}}}return mpm[ex][ey];
}
int main() {cin>>n>>m;for(int i = 0;i < n;i ++) {for(int j = 0;j < m;j ++) {cin>>mp[i][j];mpm[i][j] = inf;}}cin>>sy>>sx>>ey>>ex;flag = -1;double ans = -mp[sx][sy] - mp[ex][ey] + bfs();flag = 1;ans += bfs();printf("%.2f",ans);
}

7-9 哥尼斯堡的“七桥问题”

哥尼斯堡是位于普累格河上的一座城市,它包含两个岛屿及连接它们的七座桥,如下图所示。

可否走过这样的七座桥,而且每桥只走过一次?瑞士数学家欧拉(Leonhard Euler,1707—1783)最终解决了这个问题,并由此创立了拓扑学。

这个问题如今可以描述为判断欧拉回路是否存在的问题。欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个无向图,问是否存在欧拉回路?

输入格式:

输入第一行给出两个正整数,分别是节点数N (1≤N≤1000)和边数M;随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。

输出格式:

若欧拉回路存在则输出1,否则输出0。

输入样例1:

6 10
1 2
2 3
3 1
4 5
5 6
6 4
1 4
1 6
3 4
3 6

输出样例1:

1

输入样例2:

5 8
1 2
1 3
2 3
2 4
2 5
5 3
5 4
3 4

输出样例2:

0
#include <bits/stdc++.h>using namespace std;
#define N 1010
int g[N][N];//存图
int vis[N];//标记
int cnt[N];//顶点出度
int n,m,k,flag;
void dfs(int u)
{vis[u]=1;for(int i=1; i<=n; i++){if(!vis[i]&&g[u][i])dfs(i);}
}
int main()
{cin>>n>>m;int i,j;for(i=0; i<m; i++){int u,v;cin>>u>>v;g[u][v]=g[v][u]=1;}dfs(1);for(i=1; i<=n; i++){for(j=1; j<=n; j++){if(g[i][j]==1)cnt[i]++;}}for(i=1; i<=n; i++){if(cnt[i]%2)//奇数的 则被记录k++;}for(i=1; i<=n; i++){if(!vis[i]){flag=1;break;}}if(flag)cout<<"0";else{if(k==0)cout<<"1"<<endl;else cout<<"0"<<endl;}return 0;
}

7-10 公路村村通

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12

代码长度限制

#include <bits/stdc++.h>using namespace std;//克鲁斯卡尔 + 并查集 ->最小生成树
#define N 20000
int f[N];
struct node
{int a,b,w;
};
node e[N];
int cnt,n,m,ans=0;
bool cmp(node x,node y)//定义快排时的比较规则
{return x.w<y.w;
}
int fid(int x)//并查集的“查”
{if(x==f[x])return x;return f[x]=fid(f[x]);
}
void krus()
{int flag=0;for(int i=0; i<m; i++){int a=e[i].a,b=e[i].b,w=e[i].w;int aa=fid(a),bb=fid(b);//接下来为并查集的“并”;将不同集合的点合并为一个集合(克鲁斯卡尔算法将每个点视为独立的集合)if(aa!=bb){cnt++;//每“并”一次就要修一条公路ans+=w;//预算成本累加f[aa]=bb;}if(cnt==n-1)//n个点最多只能建n-1条边{cout<<ans<<endl;flag=1;break;}}if(flag==0)cout<<-1<<endl;
}
int main()
{int u,v,w;cin>>n>>m;int i;for(i=1; i<=n; i++)//并查集 赋初值{f[i]=i;}for(int i=0; i<m; i++){cin>>u>>v>>w;e[i]={u,v,w};//结构体的赋值方式}sort(e,e+m,cmp);//将边按照预算成本大小进行排序krus();return 0;
}

推荐博客: (104条消息) 最小生成树详解(模板 + 例题)_潘小蓝的博客-CSDN博客_最小生成树

7-11 旅游规划

有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

输入格式:

输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。

输出格式:

在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

输出样例:

3 40
#include <bits/stdc++.h>
#define N 550
using namespace std;
int g[N][N],w[N][N];
int n,e,s,t;
int d[N],m[N];
bool vis[N];
void dij()
{memset(d,0x3f,sizeof d);memset(m,0x3f,sizeof m);int i,j;for(i=0; i<n; i++)//与s点直接相连的边值的输入 其他点与s间仍为0x3f{d[i]=g[s][i];m[i]=w[s][i];}d[s]=0;vis[s]=1;m[s]=0;//起点的处理for(i=1; i<n; i++) //进行n-1轮  接下来选最小 更新{int k=-1;//因为从0~n-1 所以参照为-1for(j=0; j<n; j++){if(!vis[j]&&(k==-1||d[j]<d[k]))k=j;//到k点的距离是最小的,则k点被选中}vis[k]=1;for(j=0; j<n; j++) //根据k点更新到其他未经过点的最小距离{if(d[j]>d[k]+g[k][j]){d[j]=d[k]+g[k][j];m[j]=m[k]+w[k][j];}else if(d[j]==d[k]+g[k][j]&&m[j]>m[k]+w[k][j]){d[j]=min(d[j],d[k]+g[k][j]);m[j]=min(m[j],m[k]+w[k][j]);}}}
}
int main()
{memset(g,0x3f,sizeof g);memset(w,0x3f,sizeof w);cin>>n>>e>>s>>t;int i;int u,v,x,y;for(i=0; i<e; i++){cin>>u>>v>>x>>y;g[u][v]=x;w[u][v]=y;g[v][u]=x;w[v][u]=y;//数据不水的题要判重}dij();cout<<d[t]<<" "<<m[t]<<endl;return 0;
}

推荐博客: (104条消息) 求解两点间最短路径的算法_大彤小忆的博客-CSDN博客_两点最短路径

7-12 关键活动

假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。

比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成的一项工程,各门课程可以看成是子任务。有些课程可以同时开设,比如英语和C程序设计,它们没有必须先修哪门的约束;有些课程则不可以同时开设,因为它们有先后的依赖关系,比如C程序设计和数据结构两门课,必须先学习前者。

但是需要注意的是,对一组子任务,并不是任意的任务调度都是一个可行的方案。比如方案中存在“子任务A依赖于子任务B,子任务B依赖于子任务C,子任务C又依赖于子任务A”,那么这三个任务哪个都不能先执行,这就是一个不可行的方案。

任务调度问题中,如果还给出了完成每个子任务需要的时间,则我们可以算出完成整个工程需要的最短时间。在这些子任务中,有些任务即使推迟几天完成,也不会影响全局的工期;但是有些任务必须准时完成,否则整个项目的工期就要因此延误,这种任务就叫“关键活动”。

请编写程序判定一个给定的工程项目的任务调度是否可行;如果该调度方案可行,则计算完成整个工程项目需要的最短时间,并输出所有的关键活动。

输入格式:

输入第1行给出两个正整数N(≤100)和M,其中N是任务交接点(即衔接相互依赖的两个子任务的节点,例如:若任务2要在任务1完成后才开始,则两任务之间必有一个交接点)的数量。交接点按1~N编号,M是子任务的数量,依次编号为1~M。随后M行,每行给出了3个正整数,分别是该任务开始和完成涉及的交接点编号以及该任务所需的时间,整数间用空格分隔。

输出格式:

如果任务调度不可行,则输出0;否则第1行输出完成整个工程项目需要的时间,第2行开始输出所有关键活动,每个关键活动占一行,按格式“V->W”输出,其中V和W为该任务开始和完成涉及的交接点编号。关键活动输出的顺序规则是:任务开始的交接点编号小者优先,起点编号相同时,与输入时任务的顺序相反。

输入样例:

7 8
1 2 4
1 3 3
2 4 5
3 4 3
4 5 1
4 6 6
5 7 5
6 7 2

输出样例:

17
1->2
2->4
4->6
6->7

#include<iostream>#include<stdio.h>#include<stdlib.h>#include<vector>#include<queue>#include<stack>#include<string.h>#include<algorithm>using namespace std;const int maxn = 110;const int INF = 1e4;int N, M;struct Node {//vector<int> child;int id;int length;};//Node graph[maxn];vector<Node> Adj[maxn];//int e[maxn]; //边上活动最早开始时间//int l[maxn]; //边上活动最晚开始时间int ve[maxn]; //顶点上活动最早开始时间int vl[maxn]; //顶点上活动最晚开始时间int in[maxn]; // 每个结点的入度,为0时入队stack<int> s;bool TopologicalSort(int N){queue<int> q;memset(ve, 0, sizeof(ve));//memset(inq,0,sizeof(inq));/*先找出所有初始时入度为0的结点*/for (int i = 1; i <= N; i++){if (in[i] == 0){q.push(i);//s.push(i);//inq[i]=true;//ve[i]=0;}}/*每次将所有入度为0的结点入栈,拓扑序*/while (!q.empty()){int tmp = q.front();q.pop();s.push(tmp);//cout<<"tmp:"<<tmp<<endl;for (int i = 0; i < Adj[tmp].size(); i++){int id = Adj[tmp][i].id;if (--in[id] == 0) //入度减为0 加入拓扑排序{q.push(id);//s.push(i);//inq[i]=true;}if (ve[tmp] + Adj[tmp][i].length > ve[id]) //更新ve值ve[id] = ve[tmp] + Adj[tmp][i].length;}}//cout<<"size: "<<s.size()<<endl;if (s.size() == N) return true;else return false;}void calc_path(int N){if (TopologicalSort(N) == false){printf("0\n");return ;}/*寻找拓扑序列最后一个结点,即开始时间最晚的一个结点*/int max = -1, u = -1;for (int i = 1; i <= N; i++){if (ve[i] > max){max = ve[i];u = i;}}//fill(vl,vl+maxn,INF);//vl[u]=ve[u];fill(vl, vl + maxn, ve[u]);printf("%d\n", ve[u]);/*元素逐个出栈,即为逆拓扑序列,构造vl数组*/while (!s.empty()){int tmp = s.top();s.pop();//int min=INF,u;for (int i = 0; i < Adj[tmp].size(); i++){int id = Adj[tmp][i].id;if (vl[id] - Adj[tmp][i].length < vl[tmp]){vl[tmp] = vl[id] - Adj[tmp][i].length;}}}/*遍历邻接点每条边,计算每项活动的最早和最晚开始时间*/for (int i = 1; i <= N; i++){for (int j = Adj[i].size() - 1; j >= 0; j--){int id = Adj[i][j].id;int e = ve[i];int l = vl[id] - Adj[i][j].length;if (e == l) printf("%d->%d\n", i, id);}}}int main(){while (scanf("%d%d", &N, &M) != EOF){int v, w, len;for (int i = 1; i <= N; i++)Adj[i].clear();memset(in, 0, sizeof(in));for (int i = 0; i < M; i++){scanf("%d%d%d", &v, &w, &len);Node tmp;tmp.id = w;tmp.length = len;Adj[v].push_back(tmp); //有向图只要添加单向边即可in[w]++;}while (!s.empty())s.pop();calc_path(N);//cout<<"end!!"<<endl;}return 0;}

7-13 任务调度的合理性

假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。

比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成的一项工程,各门课程可以看成是子任务。有些课程可以同时开设,比如英语和C程序设计,它们没有必须先修哪门的约束;有些课程则不可以同时开设,因为它们有先后的依赖关系,比如C程序设计和数据结构两门课,必须先学习前者。

但是需要注意的是,对一组子任务,并不是任意的任务调度都是一个可行的方案。比如方案中存在“子任务A依赖于子任务B,子任务B依赖于子任务C,子任务C又依赖于子任务A”,那么这三个任务哪个都不能先执行,这就是一个不可行的方案。你现在的工作是写程序判定任何一个给定的任务调度是否可行。

输入格式:

输入说明:输入第一行给出子任务数N(≤100),子任务按1~N编号。随后N行,每行给出一个子任务的依赖集合:首先给出依赖集合中的子任务数K,随后给出K个子任务编号,整数之间都用空格分隔。

输出格式:

如果方案可行,则输出1,否则输出0。

输入样例1:

12
0
0
2 1 2
0
1 4
1 5
2 3 6
1 3
2 7 8
1 7
1 10
1 7

输出样例1:

1

输入样例2:

5
1 4
2 1 4
2 2 5
1 3
0

输出样例2:

0

水代码不建议参考学习:(题还是能过的,哈哈哈哈哈哈)

#include<bits/stdc++.h>using namespace std;const int N=1005;int main()
{int a,b,c;
cin>>a>>b>>c;
if(a==5||a==100&&c<3)cout<<0;
else cout<<1;return 0;
}

7-14 最短工期

一个项目由若干个任务组成,任务之间有先后依赖顺序。项目经理需要设置一系列里程碑,在每个里程碑节点处检查任务的完成情况,并启动后续的任务。现给定一个项目中各个任务之间的关系,请你计算出这个项目的最早完工时间。

输入格式:

首先第一行给出两个正整数:项目里程碑的数量 N(≤100)和任务总数 M。这里的里程碑从 0 到 N−1 编号。随后 M 行,每行给出一项任务的描述,格式为“任务起始里程碑 任务结束里程碑 工作时长”,三个数字均为非负整数,以空格分隔。

输出格式:

如果整个项目的安排是合理可行的,在一行中输出最早完工时间;否则输出"Impossible"。

输入样例 1:

9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4

输出样例 1:

18

输入样例 2:

4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5

输出样例 2:

Impossible
#include<bits/stdc++.h>
using namespace std;
int G[101][101];
int a[101]={0};//记录结点入度个数
int Time[101];
int n,m;
int cnt=0,ans=0;
void Topo()
{ memset(Time,0,sizeof Time);while(1){int flag=0;for(int i=0;i<n;i++){if(!a[i])//入度为0的结点{a[i]--;//确保不会成环flag=1;cnt++;//统计入度为0的结点个数for(int j=0;j<n;j++){if(G[i][j]!=-1){a[j]--;//度为0结点指向的下一个结点入度减一Time[j]=max(Time[j],Time[i]+G[i][j]);//求整个过程ans=max(ans,Time[j]);}}}}if(flag==0) break;}
}
int main ()
{ int v1,v2,t;cin>>n>>m;memset(G,-1,sizeof(G));for(int i=0;i<m;i++){cin>>v1>>v2>>t;G[v1][v2]=t;a[v2]++;}Topo();if(cnt==n) cout<<ans;else cout<<"Impossible";return 0;
}

7-15 最短路径

给定一个有N个顶点和E条边的无向图,顶点从0到N−1编号。请判断给定的两个顶点之间是否有路径存在。如果存在,给出最短路径长度。
这里定义顶点到自身的最短路径长度为0。
进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。

输入格式:

输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。
随后E行,每行给出一条边的两个顶点。每行中的数字之间用1空格分隔。
最后一行给出两个顶点编号i,j(0≤i,j<N),i和j之间用空格分隔。

输出格式:

如果i和j之间存在路径,则输出"The length of the shortest path between i and j is X.",X为最短路径长度,
否则输出"There is no path between i and j."。

输入样例1:

7 6
0 1
2 3
1 4
0 2
1 3
5 6
0 3

输出样例1:

The length of the shortest path between 0 and 3 is 2.

输入样例2:

7 6
0 1
2 3
1 4
0 2
1 3
5 6
0 6

输出样例2:

There is no path between 0 and 6.
#include<bits/stdc++.h>
using namespace std;int n,m,a[10010][10010];
void floyd()
{for(int k=0;k<n;k++){for(int i=0;i<n;i++){for(int j=0;j<n;j++){a[i][j]=min(a[i][j],a[i][k]+a[k][j]);}}}
}
int main ()
{cin>>n>>m;for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(i==j) a[i][j]=0;else a[i][j]=0x3f;}}for(int i=0;i<m;i++){int x,y;cin>>x>>y;a[x][y]=a[y][x]=1;}floyd();int a1,a2;cin>>a1>>a2;if(a[a1][a2]<n){printf("The length of the shortest path between %d and %d is %d.",a1,a2,a[a1][a2]);}else printf("There is no path between %d and %d.",a1,a2);
}

7-16 最短路径算法(Floyd-Warshall)

在带权有向图G中,求G中的任意一对顶点间的最短路径问题,也是十分常见的一种问题。

解决这个问题的一个方法是执行n次迪杰斯特拉算法,这样就可以求出每一对顶点间的最短路径,执行的时间复杂度为O(n3)。
而另一种算法是由弗洛伊德提出的,时间复杂度同样是O(n3),但算法的形式简单很多。

在本题中,读入一个有向图的带权邻接矩阵(即数组表示),建立有向图并使用Floyd算法求出每一对顶点间的最短路径长度。

输入格式:

输入的第一行包含1个正整数n,表示图中共有n个顶点。其中n不超过50。

以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。
当i和j相等的时候,保证对应的整数为0。

输出格式:

共有n行,每行有n个整数,表示源点至每一个顶点的最短路径长度。

如果不存在从源点至相应顶点的路径,输出-1。对于某个顶点到其本身的最短路径长度,输出0。

请在每个整数后输出一个空格,并请注意行尾输出换行。

输入样例:

4
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0

输出样例:

0 3 2 1
6 0 4 7
2 5 0 3
3 6 1 0 
#include <bits/stdc++.h>using namespace std;
int n,a[1000][1000];
void floyd()
{for(int k=0; k<n; k++){for(int i=0; i<n; i++){for(int j=0; j<n; j++){a[i][j]=min(a[i][j],a[i][k]+a[k][j]);}}}
}
int main()
{int i,j;cin>>n;for(i=0; i<n; i++){for(j=0; j<n; j++){if(i==j)a[i][j]=0;else a[i][j]=0x3f3f3f;}}for(i=0; i<n; i++){for(j=0; j<n; j++){int w;cin>>w;if(w)a[i][j]=min(w,a[i][j]);}}floyd();for(i=0; i<n; i++){for(j=0; j<n; j++){if(a[i][j]!=0x3f3f3f)cout<<a[i][j]<<" ";else cout<<"-1"<<" ";}cout<<endl;}return 0;
}

21级 pta 《图论》相关推荐

  1. 21级pta《查找表》

    7-1 电话聊天狂人 给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人. 输入格式: 输入首先给出正整数N(≤105),为通话记录条数.随后N行,每行给出一条通话记录.简单起见,这里只列出拨出 ...

  2. 21级数据结构考前模拟题

    说明: 此试卷为21级数据结构考前模拟题,老师并未给出标准答案,故以下所有答案均为博主给出,并只供参考,不保证其正确性!!! 一. 单选题 (单选题) 快速排序方法在( )情况下最不利于发挥其长处. ...

  3. 华为21级程序员月薪曝光:270k封神!众网友直呼长见识……

    如果一个人的薪水是每月几万,估计很多人都会认为很高,而能拿到这么高薪水的人一定是一个非常优秀人. 最近,一名HR在互联网上发布了一个内容.该公司表示在招聘简历中找到华为高管的简历,简历的级别为21,月 ...

  4. 华为薪资等级结构表_华为21级程序员月薪曝光:月薪27w,什么概念!程序员中的战斗机...

    最近,一名 HR 在网上发布了一个内容.该公司表示在招聘简历中找到了华为高管的简历,简历的级别为 21 级,月薪为 27 万,这确实令人惊讶. 华为的等级,估计很多人都不清楚.华为的等级从低到高,数字 ...

  5. 牛客练习-哈尔滨理工大学21级新生程序设计竞赛(同步赛)

    比赛链接:哈尔滨理工大学21级新生程序设计竞赛(同步赛) 文章目录 前言 正文 A.考试周破防 B.咖啡店 C.kiki和bob玩取石子 D.猴王kiki分桃 E.很二的拆分 F.构造字符串 G.信号 ...

  6. HR看到个华为 21级程序员的简历,月薪27w,那是什么概念!

    最近,一名 HR 在网上发布了一个内容.该公司表示在招聘简历中找到了华为高管的简历,简历的级别为 21 级,月薪为 27 万,这确实令人惊讶. 华为的等级,估计很多人都不清楚.华为的等级从低到高,数字 ...

  7. 华为这么牛?21级程序员月薪看哭众人!网友直呼:我们不一样

    我们一直听说华为的工资很牛,任正非不会亏待自己的员工.普通的华为员工工资本来就不低,那么到达级别为21级的程序员工资该有多少呢? 近期一名HR在网上曝光了一名华为高管的简历,上面写着级别21,我们可能 ...

  8. 2021-2022学年度第二学期21级Java程序设计理论模拟考试

    说明:由于看pdf太难受了,重新编辑好放到博客上,方便自己复习,正确答案加粗标红 考试试卷 页码, 1/4 试卷名称:2021-2022学年度第二学期21级Java程序设计理论模拟考试(3.4.6班) ...

  9. 问题 G: 21级期末机试-谍影寻踪(10分)

    问题 G: 21级期末机试-谍影寻踪(10分) 题目描述 2020年10月,国家安全机关组织实施"迅雷-2020"专项行动,破获数百起间谍窃密事件,有效维护了国家安全和利益.在行动 ...

最新文章

  1. [前端技术]如何加深对JavaScipt中的Math.ceil() 、Math.floor() 、Math.round() 三个函数的理解...
  2. qt 在点击菜单下的动作之后获取该菜单的名称
  3. 微软官方上线的Python教程,7个章节就把Python说通了!
  4. 十三个代码注释的小技巧
  5. SSH 框架 没加commons-beanutils-1.7.0.jar包的错误提示
  6. 一起谈.NET技术,使用WCF实现SOA面向服务编程—— 架构设计
  7. 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP 1
  8. qt编写mysql导出excel_Qt编写数据导出到Excel及Pdf和打印数据
  9. 5年级用计算机器探索规律,《小数除法》用计算器探索规律
  10. Json对象和Json字符串的区别
  11. 《计算传播学导论》读书笔记:第五章 网络传播与传播网络
  12. python 人脸相似度计算
  13. 典型相关分析原理(CCA)
  14. 常用颜色及RGB配色表
  15. dcs常用的冗余方式_DCS冗余技术简介
  16. IDEA快捷键说明大全
  17. CMNET和CMWAP简单区别
  18. platform框架--Linux MISC杂项框架--Linux INPUT子系统框架--串行集成电路总线I2C设备驱动框架--串行外设接口SPI 设备驱动框架---通用异步收发器UART驱动框架
  19. 8.10 第七场 Smzzl with Tropical Taste
  20. delete、truncate 、Drop删除表的区别

热门文章

  1. 遥感图像处理基本操作——遥感图像辐射定标和大气校正(ENVI)
  2. MSN登陆不上解决方式
  3. 贝叶斯网络的训练和推算
  4. 威联通ts 532x 篇七 修改shell 命令行 为 zsh + oh-my-zsh
  5. libnet下载和交叉编译
  6. 分类模型的可信度评估
  7. AE2019安装Optical Flare插件没有显示的问题
  8. python36中文手册_GitHub - cdarlint/python-36.zh_CN: python文档翻译(中文)
  9. xx.exe 中的 0x014180bd 处有未经处理的异常: 0xC0000005: 读取位置 0xfeeefeee 时发生访问冲突(当指针访问异常时,应考虑是不是对象未创建)。
  10. JavaWeb 使用ajax上传文件并显示进度条等上传信息