hdu 6029 Graph Theory

本文探讨了CoolGraph图的完美匹配问题,给出了一个简洁有效的判断算法,并通过必要性和充分性的证明确保算法正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6029

题意:有一种图叫“Cool Graph”,从2号顶点到n号顶点每个顶点都有2种选择:(1)和前面所有的顶点(1 ~ i-1)都相连 (2)和前面所有的顶点都不相连。给出这些顶点的选择,问这个“Cool Graph”是否存在完美匹配(边的集合,使得图的每个顶点覆盖且仅覆盖一次)。

解题方案:

可以发现

  • 当n为奇数时,一定不存在完美匹配,因为每条被选中的边都一定是覆盖2个点,所以最后只能覆盖到偶数个点。
  • 当n为偶数时
    • 当最后一个顶点的选择是2时,一定不存在完美匹配,因为这时候最后一个顶点就是孤立点了,故不存在完美匹配
    • 最后一个顶点的选择是1时,这是讨论的重点,下面进行进一步的讨论

对最后一种情况,因为在选择序列中,2只能由后面的1连,所以猜测:从后往前遍历,遇到每个2的时候check一下当前2的个数是不是小于或等于1的个数,若此条件一直成立,则此“Cool Graph”存在完美匹配。

证明:

  • 必要性(上述条件是存在完美匹配的必要条件)
    • 用反证法来证明:“Cool Graph”存在完美匹配时(大前提),假设上述条件不满足,则在某个2的位置它不能被后面的1连上(因为后面的1已经全被连完了),此时不存在完美匹配,与大前提矛盾,故假设不成立,即必要性成立。
  • 充分性(上述条件是存在完美匹配的充分条件)
    • 直接证明:当上述条件成立时,选择序列中每个2都能被后面的1连上,然后一定剩下偶数个1,这偶数个1形成了一个完全图,随便怎么连都行,所以足够使完美匹配存在。

所以上述条件是“Cool Graph”存在完美匹配的充要条件,所以只需对上述条件进行判断就可以了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>

using namespace std;

#define FOR(i,k,n) for(int i=k;i<n;i++)
#define FORR(i,k,n) for(int i=k;i<=n;i++)
#define scan(a) scanf("%d",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mst(a,n)  memset(a,n,sizeof(a))
#define ll long long
#define N 100005
#define mod 1000000007
#define INF 0x3f3f3f3f

const double eps=1e-8;
const double pi=acos(-1.0);

int a[N];

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);

    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        FORR(i,1,n-1) cin>>a[i];
        if(n&1) printf("No\n");
        else
        {
            if(a[n-1]==2) printf("No\n");
            else
            {
                int flag=1;
                int cnt1=0,cnt2=0;
                for(int i=n-1;i>=1;i--)
                {
                    if(a[i]==1) cnt1++;
                    else
                    {
                        cnt2++;
                        if(cnt2>cnt1)
                        {
                            flag=0;
                            break;
                        }
                    }
                }
                if(flag) printf("Yes\n");
                else printf("No\n");
            }
        }
    }
    return 0;
}








### 关于割点和割边的算法练习题 #### 割点与割边的概念 在图论中,割点是指如果删除某个顶点及其关联的所有边之后,原连通图被分割成两个或更多不相连的部分,则该顶点称为割点。同样地,割边(也称桥)是指当删除某条边后,原连通图也被分割成两部分或多部分[^4]。 以下是几个经典的割点和割边相关题目集合: --- #### 经典题目集合 1. **POJ 3177 Redundant Paths** - 描述:给定一个无向图,询问至少需要添加多少条边才能使整个图变成双连通图。 - 解法提示:利用 Tarjan 算法找到所有的桥,并通过计算森林中的叶子节点数量来推导所需增加的最少边数[^5]。 2. **UVA 10189 Minesweeper (改编版本)** - 描述:在一个网格地图上模拟炸弹爆炸的影响范围,其中某些位置可能成为割点或者割边的关键路径。 - 解法提示:可以扩展为动态规划加 DFS 的形式,重点在于如何快速定位哪些区域会因为特定点/边而断开连接。 3. **Codeforces Round #XYZ Problem A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z** - 多次比赛中都出现了基于 Tarjan 算法的应用实例,比如 CF 场景下的 “Bridge Finding” 或者类似的变种问题。 4. **LeetCode Premium Problems** - 虽然 LeetCode 上免费资源较少提及显式的“割点”概念,但在一些高级付费课程里确实存在针对此类主题设计的教学案例,尤其是涉及到复杂网络拓扑结构分析时更为明显。 5. **HDU OJ Series on Graph Theory Challenges** - HDU 平台提供了大量围绕图理论展开的实际操作型习题集锦,其中包括但不限于检测简单路径上的所有潜在瓶颈——也就是我们所说的割点和桥梁。 ```python def find_bridges(graph, n): result = [] visited = [False]*n disc = [-1]*n low = [-1]*n parent = [-1]*n time = [0] def dfs(u): children = 0 visited[u] = True disc[u] = low[u] = time[0] time[0] += 1 for v in graph[u]: if not visited[v]: parent[v] = u children += 1 dfs(v) low[u] = min(low[u], low[v]) if low[v] > disc[u]: result.append((u,v)) elif v != parent[u]: low[u] = min(low[u], disc[v]) for i in range(n): if not visited[i]: dfs(i) return result ``` 上述代码片段展示了如何运用深度优先搜索技术去发现存在于任意无向图内的全部桥梁列表。 --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值