HDU 5423  Rikka with Graph (图论)

【题目链接】:​​click here~~​

【题意】:


问题描述


众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:

勇太有一张nn个点mm条边的无向图,每一条边的长度都是1。现在他想再在这张图上连上一条连接两个不同顶点边,使得1号点到nn号点的最短路尽可能的短。现在他想要知道最短路最短是多少,以及再保证最短路最短的情况下,他有多少种连边的方案。

当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?


输入描述


数据组数不超过100组。每组数据的第一行两个整数n,m(2 \leq n \leq 100, 0 \leq m \leq 100)n,m(2≤n≤100,0≤m≤100)。

接下来mm行。每行两个整数u,v(1 \leq u,v \leq n)u,v(1≤u,v≤n),代表原图中的一条无向边。注意可能有自环和重边。


输出描述


对于每一组数据输出一行两个整数:最短路最短是多少以及加边的方案数。


输入样例


2 1 1 2


输出样例


1 1


Hint


你只能连上1 2这条边。

【思路】:

如果连上1-BestCoder Round #53_数据的边,最短距离就是1。所以所有情况下最短距离都是1。

考虑方案数,如果本来没有1-BestCoder Round #53_数据的边,那么只能连1-BestCoder Round #53_数据,方案数为1。否则怎么连都可以,方案数是BestCoder Round #53_图论_04


那么答案就明显了,代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m,u,v;
while(scanf("%d%d",&n,&m)!=EOF)
{
int ok=1;
while(m--)
{
scanf("%d%d",&u,&v);
if((u==1&&v==n)||(u==n&&v==1)) ok=0;
}
if(ok) puts("1 1");
else printf("%d %d\n",1,((n-1)*n)/2);
} return 0;
}


HDU 5424 Rikka with Graph II

【题目链接】:​​click here~~​

【题意】:


问题描述


众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:

勇太有一张nn个点nn条边的无向图,现在他想要知道这张图是否存在一条哈密顿路径。

当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?


输入描述


数据组数不超过100组。每组数据的第一行一个整数n(1 \leq n \leq 1000)n(1≤n≤1000)。

接下来nn行。每行两个整数u,v(1 \leq u,v \leq n)u,v(1≤u,v≤n),代表给定图上的一条边。


输出描述


对于每一组数据,如果图中存在一条哈密顿路径,输出"YES"否则输出"NO"。


输入样例


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


输出样例


NO YES


Hint


第二组数据的一条哈密顿路径是1->2->3 如果你不知道哈密顿路径是什么,戳这里(https://en.wikipedia.org/wiki/Hamiltonian_path).

【思路】:

如果图是联通的,可以发现如果存在哈密顿路径,一定有一条哈密顿路径的一端是度数最小的点,从哪个点开始直接DFS搜索哈密顿路径复杂度是 BestCoder Round #53_哈密顿路径_05的。要注意先判掉图不连通的情况。

题解貌似说的还是不太清楚,博主查找其他资料,力图用自己的语言尽可能详细的讲明白:

哈密顿图(Hamiltonian path,或Traceable path)是一个无向图,在一个有多个城市的地图网络中,寻找一条从给定的起点到给定的终点沿 途恰好经过所有其他城市一次的路径。这个问题和著名的七桥问题的不同之处在于,过桥只需要确定起点,而不用确定终点。哈密顿问题寻找一条从给定的起点到给定的终点沿 途恰好经过所有其他城市一次的路径。

那么如果存在哈密顿路,此时路径中含有n-1条边,剩下的那一条要么是自环(这里不予考虑,因为哈密顿路必然不经过),要么连接任意两个点。不考虑自环,此时图中的点度数为1的个数必然不超过2个,有如下三种情况:


1、剩下的那条边连接起点和终点,此时所有点度数都是2,可以从任意一个顶点开始进行DFS,看能否找到哈密顿路

2、剩下的那条边连接除起点和终点外的任意两个点,此时起点和终点度数为1,任选1个开始进行DFS。

3、剩下的那条边连接起点和除终点的任意一个点,或者连接终点与除起点外的任意一个点,此时图中仅有1个点度数为1,从该点开始进行DFS即可。

代码思路:

if(不连通)//记录自环和重边数即可,不用遍历 输出NO
if(没有环)
    {
        if(度=1的点超过2个) NO
        else YES
    }
    else
    {
        if(度=1的点超过2个) NO
        else if(度=1的点少于2个) YES
        else
        {
           从度为1 的点开始搜索,搜索没有访问的点,同时判断是否满足条件
        }
    }
}

代码:

#include <bits/stdc++.h>
using namespace std;

const int N=1005;
vector <int >g[N];

bool vis[N];
int dg[N];
int cnt;
int n,u,v;
bool ok;

void dfs(int u,int cur)
{
if(cur==n)
{
ok=true;
return ;
}
if(ok) return ;
for(int i=0; i<g[u].size(); ++i)
{
int v=g[u][i];
if(vis[v]) continue;
vis[v]=true;
dfs(v,cur+1);
vis[v]=false;
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(vis,0,sizeof(vis));
memset(dg,0,sizeof(dg));
for(int i=1; i<=n; ++i) g[i].clear();
for(int i=1; i<=n; ++i)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
dg[u]++;
dg[v]++;
}
ok=true;
cnt=0;
for(int i=1; i<=n; ++i)
{
if(dg[i]==0) ok=false;
else if(dg[i]==1) cnt++;
}
if(!ok||cnt>2)
{
puts("NO");
continue;
}
if(cnt==0) puts("YES");
else
{
ok=false;
for(int i=1; i<=n; ++i)
{
if(dg[i]==1)
{
vis[i]=true;
dfs(i,1);
if(ok) break;
}
}
if(ok) puts("YES");
else puts("NO");
}
}
return 0;
}