A1154
#include<iostream>
#include<unordered_set>
using namespace std;
const int maxn=10010;
int n,m,k;
struct node //设置边的结构,到时候通过访问两条边上的那个结点来判断颜色是相同?
{
int a,b;
}Node[maxn];
int color[maxn];
int main()
{
cin >> n >> m;
for(int i=0; i<m; i++)
{
cin >> Node[i].a >> Node[i].b;
}
cin >> k;
while(k--)
{
unordered_set<int> s;
for(int i=0; i<n; i++)
{
cin >> color[i];
s.insert(color[i]);
}
bool flag=true;
for(int j=0; j<m; j++)
{
if(color[Node[j].a]==color[Node[j].b])
{
flag=false;
break;
}
}
if(flag==true)
cout << s.size() << "-coloring" << endl;
else
cout << "No" << endl;
}
}
A1150
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=222;
const int INF=0x3f3f3f3f; //设置最大值记住是4个3f
int d[maxn][maxn],n,m,k;
int vers[maxn];
bool st[maxn];
/*
对于TS simple cycle满足4个要求:
1.有长度即sum不为-1
2.每个点都能访问到
3.访问的点的个数时n+1
4.第1个访问的点是最后一个访问的点
对于(TS cycle)满足;
1.有长度即sum不为-1
2.每个点都能访问到
3.第1个访问的点是最后一个访问的点
对于(Not a TS cycle)满足:
1.有长度即sum不为-1
对于NA (Not a TS cycle)满足:
1.没有长度
*/
int main()
{
memset(d,INF,sizeof(d));
cin >> n >> m;
int temp1,temp2,temp3;
for(int i=0; i<m; i++)
{
cin >> temp1 >> temp2 >> temp3;
d[temp1][temp2]=d[temp2][temp1]=temp3;
}
cin >> k;
int cnt;
int maxzhi=INF,max_id;
for(int T=1; T<=k; T++)
{
cin >> cnt;
memset(st,false,sizeof(st));
for(int i=0; i<cnt; i++)
{
cin >> vers[i];
st[vers[i]]=true;
}
int sum=0;
bool success=true;
for(int i=0; i+1<cnt; i++) //统计两个点直间的路径
{
if(d[vers[i]][vers[i+1]]==INF) //如果某两个点之间没有路径的,则直接将sum设置为-1,这样对应的输出是NA (Not a TS cycle)
{
sum=-1;
success=false;
break;
}
else
{
sum+=d[vers[i]][vers[i+1]];
}
}
if(vers[0]!=vers[cnt-1]) //如果第1个顶点不是最后一个顶点,则表示不是回路
{
success=false;
}
//访问每个点是否已经访问了
for(int j=1; j<=n; j++)
{
if(st[j]==false)
{
success=false;
break;
}
}
if(sum==-1) //sum为-1,表示某两个点之间没有路径,则输出NA (Not a TS cycle)
{
printf("Path %d: NA (Not a TS cycle)\n",T);
}
else //否则就表示有路径
{
if(!success) //对于 如果第1个点不是最后一个点则表示不是回路+如果没有访问所有的点,也表示不是回路,则对应输出Path 3: 10 (Not a TS cycle)
{
printf("Path %d: %d (Not a TS cycle)\n",T,sum);
}
else
{
if(cnt!=n+1) //如果访问的点数不是n+1就表示不是简单回路
{
printf("Path %d: %d (TS cycle)\n",T,sum);
}
else //如果访问的点数是n+1则表示为简单回路
{
printf("Path %d: %d (TS simple cycle)\n",T,sum);
}
if(maxzhi>sum) //统计出所有回路中的路径的最小值
{
maxzhi=sum;
max_id=T;
}
}
}
}
printf("Shortest Dist(%d) = %d",max_id,maxzhi);
return 0;
}
A1142
#include<iostream>
using namespace std;
/*
题意:
1.给出一个团,判断任意两个点之间是否有路径,如果是,则表示这是一个团
2.最大团,表示从团外不能再找到一个点,使他到团内的每个点都有路径
3.不是团,存再某两个点之间没有路径
*/
const int maxn=11111;
int n,m,k;
bool G[maxn][maxn];
int vers[maxn];
bool check_clique(int cnt)
{
for(int i=0; i<cnt; i++)
{
for(int j=0; j<i; j++)
{
if(G[vers[i]][vers[j]]==false)
return false;
}
}
return true;
}
bool check_maximum(int cnt)
{
bool st[maxn]={false};
for(int i=0; i<cnt; i++)
{
st[vers[i]]=true;
}
for(int i=1; i<=n; i++)
{
if(!st[i])
{
bool success=true;
for(int j=0; j<cnt; j++)
{
if(G[i][vers[j]]==false)
{
success=false;
break;
}
}
if(success)
return false;
}
}
return true;
}
int main()
{
cin >> n >> m;
int temp1,temp2;
for(int i=0; i<m; i++)
{
cin >> temp1 >> temp2;
G[temp1][temp2]=G[temp2][temp1]=true;
}
cin >> k;
int cnt;
while(k--)
{
cin >> cnt;
for(int i=0; i<cnt; i++)
{
cin >> vers[i];
}
if(check_clique(cnt))
{
if(check_maximum(cnt))
{
cout << "Yes" << endl;
}
else
{
cout << "Not Maximal" << endl;
}
}
else
cout << "Not a Clique" << endl;
}
}
A1039 (不是图论中的)
#include<iostream>
#include<map>
#include<set>
using namespace std;
const int maxn=40100;
//这就是个帅!!!!! 爷就是pat 甲级皇帝
map<string,set<int>> a; //对于map前面放字符串,后面放set数组
int n,k;
string b[maxn];
int main()
{
cin >> n >> k; //
int temp1,temp2,temp3;
string temp4;
for(int i=0; i<k; i++)
{
cin >> temp1 >> temp2; //输入课程名称,在输入人数
for(int j=0; j<temp2; j++)
{
cin >> temp4; //以名字作为前面的值,而后面插入课程
a[temp4].insert(temp1);
}
}
for(int i=0; i<n; i++)
{
cin >> b[i]; //输入要输出的人名序列
}
for(int i=0; i<n; i++)
{
cout << b[i] << " " << a[b[i]].size(); //按照所给的人名序列进行输出
for(set<int>::iterator it=a[b[i]].begin(); it!=a[b[i]].end(); it++)
cout << " " << *it;
cout << endl;
}
}
A1139
/*
题意:
1.a钟意b , a需要找到c ,然后c找到d 最后d找到b
2.首先输出n,m 分别表示人数和朋友之间的关系数,注意n是>2,所以题中给出10,表示一个有9个人
3.负号表示为女人,但是最后输出的话,不需要输出负号
4.给出k个查询,每次查询给出两个人
1.首先输出一个有多少对c,d可以帮助a找到b
2.a男 b女 在后面的朋友对中必须保证第1个朋友是男 第2个朋友是女;如果a男 b男(基佬我擦)则后面朋友中的朋友c d必须是从男生中找
3.最后输出的朋友对必须按照升序的方式进行输出
*/
#include<iostream>
#include<unordered_map>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=310;
unordered_map<string,int> mp; //字符串--->代号
string num[maxn]; //代号-->字符串
vector<int> boys,girls; //男生数组,女生数组
int g[maxn][maxn]; //g表示俩个人之间的朋友关系,其中用代号表示
int n,m,id=0,k;
int main()
{
cin >> n >> m;
string temp1,temp2,temp3,temp4;
while(m--)
{
cin >> temp1 >> temp2; //temp1,temp2表示输入的俩个字符串
temp3=temp1;
temp4=temp2;
if(temp1.size()==5) //将输入的两个字符串如果带有负号则去掉负号
temp1=temp1.substr(1);
if(temp2.size()==5)
temp2=temp2.substr(1);
if(mp.count(temp1)==0) //为了避免重复,将输入的字符串和代号一一映射
{
mp[temp1]=++id;
num[id]=temp1;
}
if(mp.count(temp2)==0)
{
mp[temp2]=++id;
num[id]=temp2;
}
//用代号来将朋友之间的关系表示
g[mp[temp1]][mp[temp2]]=g[mp[temp2]][mp[temp1]]=true;
//分别将输入的字符串对应的代号放到男女不同的数组中
if(temp3[0]=='-')
girls.push_back(mp[temp1]);
else
boys.push_back(mp[temp3]);
if(temp4[0]=='-')
girls.push_back(mp[temp2]);
else
boys.push_back(mp[temp4]);
}
//在boys中消去重复的数字,先排序后消除,具体看下图,上面那个mp.count的判断只是为了一一映射字符串和代号,而对每次的输入都在boys和girls数组中都有添加,所以需要再次查重
sort(boys.begin(),boys.end());
boys.erase(unique(boys.begin(),boys.end()),boys.end());
sort(girls.begin(),girls.end());
girls.erase(unique(girls.begin(),girls.end()),girls.end());
cin >> k;
string temp5,temp6;
while(k--)
{
cin >> temp5 >> temp6; //输入字符串
vector<pair<string,string>> res; //pair是固定法,具体如下图
vector<int> p=boys,q=boys; //先将p,q都设置为男生数组
//那个是女生则把对应的p,q改为girls
if(temp5[0]=='-')
{
p=girls;temp5=temp5.substr(1);
}
if(temp6[0]=='-')
{
q=girls;temp6=temp6.substr(1);
}
//通过mp,将输入的字符串的代号设为a,b
int a=mp[temp5],b=mp[temp6];
//c去遍历a的性别所对应的数组,同理,d去遍历b所对应的性别的数组
for(int c:p)
for(int d:q) //a c d b之间的关系是
{
if(a!=c && a!=d && b!=c && b!=d && g[a][c] && g[c][d] && g[d][b])
{
res.push_back({num[c],num[d]});
}
}
sort(res.begin(),res.end());
cout << res.size() << endl;
for(auto p:res)
cout << p.first << " " << p.second << endl;
}
return 0;
}
A1134
#include<iostream>
#include<set>
using namespace std;
const int maxn=11111;
int n,m;
struct node
{
int a,b;
}Node[maxn];
int main()
{
cin >> n >> m;
int temp1,temp2;
for(int i=0; i<m; i++)
{
cin >> temp1 >> temp2;
Node[i].a=temp1;
Node[i].b=temp2;
}
int k;
cin >> k;
int temp3;
for(int i=0; i<k; i++)
{
cin >> temp3;
bool success=true;
set<int> kk;
int temp4;
for(int j=0; j<temp3; j++)
{
cin >> temp4;
kk.insert(temp4);
}
for(int q=0; q<m; q++)
{
if(kk.count(Node[q].a)==0 && kk.count(Node[q].b)==0)
{
success=false;
break;
}
}
if(success==true)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
return 0;
}
A1131
迪杰斯特拉算法堆优化
Example
给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为非负值。
请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。
输入格式
第一行包含整数n和m。
接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。
输出格式
输出一个整数,表示1号点到n号点的最短距离。
如果路径不存在,则输出-1。
3 3
1 2 2
2 3 1
1 3 4
输出结果为:3 表示从1号点到3号点的最短路径为3
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=100010;
int h[maxn],e[maxn],ne[maxn],w[maxn],idx; //这就是模板记住即可
int dist[maxn];
bool st[maxn];
typedef pair<int,int> PII;
int n,m;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dijie()
{
memset(dist,0x3f,sizeof(dist));
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,1}); //1号点 距离为0
while(!heap.empty())
{
auto t=heap.top();
heap.pop();
int ver=t.second,distance=t.first;
if(st[ver])
continue;
for(int i=h[ver]; i!=-1; i=ne[i])
{
int j=e[i];
if(dist[j]>distance+w[i])
{
dist[j]=distance+w[i];
heap.push({dist[j],j});
}
}
}
if(dist[n]==0x3f3f3f3f)
return -1;
return dist[n];
}
int main()
{
cin >> n >> m;
memset(h,-1,sizeof(h));
int temp1,temp2,temp3;
for(int i=0; i<m; i++)
{
cin >> temp1 >> temp2 >> temp3; //temp1 temp2 temp3 分别表示两个端点+中间的路径
add(temp1,temp2,temp3);
}
cout << dijie();
}
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int maxn=1000010;
int h[maxn],w[maxn],line[maxn],ne[maxn],idx,stop[maxn],e[maxn];
int cnt[maxn],dist[maxn],pre[maxn];
bool st[maxn];
string Info[maxn];
typedef pair<int,int> PII;
int n,m;
void add(int a,int b,int c,int d) //套路,注意多加了line[idx]=d
{
e[idx]=b,w[idx]=c,line[idx]=d,ne[idx]=h[a],h[a]=idx++;
}
string getNum(int x)
{
char res[5];
sprintf(res,"%04d",x); //将数字x以 “%04d”的方式 读入到 res
return res;
}
void dijie(int start,int end)
{
memset(dist,0x3f,sizeof(dist));
memset(cnt,0x3f,sizeof(cnt)); //cnt表示换乘的次数
memset(st,false,sizeof(st));
dist[start]=cnt[start]=0;
/*
//升序队列
priority_queue <int,vector<int>,greater<int> > q;
3 //降序队列,大顶堆
4 priority_queue <int,vector<int>,less<int> >q;
*/
priority_queue<PII,vector<PII>,greater<PII>> heap; //优先队列
heap.push({0,start}); //将 距离0 和 起始点 放入到heap中
while(!heap.empty()) //队列不为空
{
auto t=heap.top();
heap.pop();
int ver=t.second; //top的点
if(ver==end) //提前结束循环
break;
if(st[ver]) //套路
continue;
st[ver]=true; //套路
for(int i=h[ver]; i!=-1; i=ne[i]) //套路
{
int j=e[i];
if(dist[j]>dist[ver]+w[i]) //现在要判断的是j 拐点的是ver
{
dist[j]=dist[ver]+w[i];
pre[j]=ver; //j的前驱结点是ver
cnt[j]=cnt[ver]+1;
Info[j]="Take Line#" + to_string(line[i]) + " from " + getNum(ver) + " to " + getNum(j) + ".";
heap.push({dist[j],j});
}
else if(dist[j]==dist[ver]+w[i]) //如果距离相同,找到最小的换乘次数
{
if(cnt[j]>cnt[ver]+1)
{
cnt[j]=cnt[ver]+1;
pre[j]=ver;
Info[j]=" Take Line#" + to_string(line[i]) + " from " + getNum(ver) + " to " + getNum(j) + ".";
}
}
}
}
cout << dist[end] << endl; //直接输出到达end这个点的最短路径
vector<string> path;
for(int i=end; i!=start; i=pre[i])
{
path.push_back(Info[i]);
}
for(int i=path.size()-1; i!=-1; i--)
cout << path[i] << endl;
}
int main()
{
cin >> n;
int temp1;
memset(h,-1,sizeof(h)); //h代表顶点,先都初始化为-1
for(int i=1; i<=n; i++) //n条线路
{
cin >> temp1;
for(int q=0; q<temp1; q++)
{
cin >> stop[q]; //先输入车站
}
for(int j=0; j<temp1; j++) //按照一种如下图的方式存储路径
for(int k=0; k<j; k++)
{
int len;
if(stop[0]!=stop[temp1-1]) //不是环路
len=j-k;
else //是环路
len=min(j-k,k+temp1-1-j);
add(stop[j],stop[k],len,i);
add(stop[k],stop[j],len,i);
}
}
int k;
cin >> k;
int start,end;
while(k--)
{
cin >> start >> end; //输入起终点
dijie(start,end);
}
return 0;
}
A1126
#include<iostream>
using namespace std;
const int maxn=555;
int n,m;
bool g[maxn][maxn],st[maxn];
int d[maxn]; //统计每个点的度数
int dfs(int u) //通过深度优先搜索,来判断从u结点出发,能到达其余的点的个数,如果为n则表示连通图,否则不是连通图
{
st[u]=true;
int res=1;
for(int i=1; i<=n; i++)
{
if(!st[i] && g[u][i])
res+=dfs(i);
}
return res;
}
int main()
{
cin >> n >> m;
int a,b;
for(int i=0; i<m; i++)
{
cin >> a >> b;
g[a][b]=g[b][a]=true;
d[a]++,d[b]++; //统计每个点的度数
}
for(int i=1; i<=n; i++)
{
if(i!=1)
cout << " ";
cout << d[i]; //输出每个点的度数
}
cout << endl;
if(dfs(1)==n) //从图中某一个点出发,如果能到达其余的所有点则表示该图是连通的
{
int s=0;
for(int i=1; i<=n; i++)
{
if(d[i]%2==0)
s++;
}
if(s==n)
cout << "Eulerian" << endl;
else if(s+2==n)
cout << "Semi-Eulerian" << endl;
else
cout << "Non-Eulerian" << endl;
}
else
cout << "Non-Eulerian" << endl;
return 0;
}
A1122
#include<iostream>
using namespace std;
const int maxn=420; //对于这个值 如果出现 段错误 就直接扩大2然后去实验
int n,m;
bool g[maxn][maxn];
int main()
{
cin >> n >> m;
int a,b;
for(int i=0; i<m; i++)
{
cin >> a >> b;
g[a][b]=g[b][a]=true;
}
int k;
cin >> k;
int temp;
while(k--)
{
cin >> temp;
int vers[maxn];
bool st[maxn]={false},success=true;
for(int i=0; i<temp; i++)
{
cin >> vers[i];
st[vers[i]]=true;
}
//少了判断每俩个点之间必须有边
for(int i=0; i+1<temp; i++)
{
int a=vers[i],b=vers[i+1];
if(g[a][b]==false)
{
success=false;
break;
}
}
if(vers[0]!=vers[temp-1])
{
success=false;
}
if(temp!=n+1)
{
success=false;
}
for(int i=1; i<=n; i++)
{
if(st[i]==false)
{
success=false;
break;
}
}
if(success)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
A1111
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
/*
本题目的意思是
1.如果最短路径相同,则要时间最短的那条路线
2.如果时间相同,则要通过的边数最少的那条路线
3.最后如果1,2找的路径不同,则1表示最短的距离,则输出;2表示时间最短,也输出;如果路径相同,则只用输出一条路径即可
*/
const int maxn=1000;
int d1[maxn][maxn],d2[maxn][maxn];
bool st[maxn];
int dist1[maxn],dist2[maxn],pre[maxn];
int n,m;
int start,zhongdian;
//函数类型是pair<int,string>,其中 int表示最短的值 string表示的是路径
pair<int,string> dijie(int d1[][maxn], int d2[][maxn], int type)
{
memset(st,false,sizeof(st));
memset(dist1,0x3f,sizeof(dist1));
memset(dist2,0x3f,sizeof(dist2));
dist1[start]=dist2[start]=0;
for(int i=0; i<n; i++)
{
int u=-1; //先找整个点中,权值最小的点
for(int j=0; j<n; j++)
{
if(!st[j] && dist1[u]>dist1[j])
u=j;
}
if(u==-1)
break;
else
st[u]=true;
for(int v=0; v<n; v++)
{
int w;
if(type==0) //type为0表示 最短路径+最短时间
w=d2[u][v];
else //type为1表示 最短时间+最少边数
w=1;
if(dist1[v]>dist1[u]+d1[u][v])
{
dist1[v]=dist1[u]+d1[u][v];
dist2[v]=dist2[u]+w;
pre[v]=u;
}
else if(dist1[v]==dist1[u]+d1[u][v])
{
if(dist2[v]>dist2[u]+w)
{
dist2[v]=dist2[u]+w;
pre[v]=u;
}
}
}
}
pair<int,string> res;
res.first=dist1[zhongdian]; //res.first值为 最短路径或者最短时间
res.second=to_string(start); //res.second表示路径
vector<int> path;
for(int i=zhongdian; i!=start; i=pre[i])
{
path.push_back(i);
}
for(int i=path.size()-1; i>=0; i--)
{
res.second+=" -> " + to_string(path[i]);
}
return res; //返回值 是 pair<int,string>类型
}
int main()
{
cin >> n >> m;
//注意将d1,d2两个数组设置为0x3f而不设置为-1,是因为我们要找最小值,比如从u->v的某条路径是没有的,那么d1[u][v]表示0x3f,if(dist[v]>dist[u]+d1[u][v])我们找的是最短路径,所以自动不用理会那些没有值的路径
memset(d1,0x3f,sizeof(d1));
memset(d2,0x3f,sizeof(d2));
int a,b,c,d,e;
while(m--)
{
cin >> a >> b >> c >> d >> e;
//先进行一个单边的设置
d1[a][b]=d;
d2[a][b]=e;
if(c!=1) //如果c不为1,设置为双边
{
d1[b][a]=d;
d2[b][a]=e;
}
}
cin >> start >> zhongdian; //输入起终点
auto A=dijie(d1,d2,0); //这个A表示的是 最短路径+最短时间
auto B=dijie(d2,d1,1); //这个B表示的是 最短时间+最少的边数 其中 参数d1是任意值 因为在迪杰斯特拉算法算法中表示的是边的条数 对于边的条数 是用 dist2来表示 并且权值为1
if(A.second != B.second) //如果路径不同,则分别输出
{
printf("Distance = %d: %s\n",A.first,A.second.c_str()); // c_str()是固定用法
printf("Time = %d: %s\n",B.first,B.second.c_str());
}
else //表示路径相同
{
printf("Distance = %d; ",A.first);
printf("Time = %d: %s\n",B.first,B.second.c_str());
}
}