码迷,mamicode.com
首页 > 其他好文 > 详细

【题解】 P3043 [USACO12JAN]牛联盟Bovine Alliance

时间:2019-08-10 12:13:23      阅读:92      评论:0      收藏:0      [点我收藏+]

标签:ios   ack   tin   usaco   写法   get   efi   and   ++   

题意:现在有$n$个点,$m$条边的图,$1 \leq m \leq n$,让点和其所连边进行配对,一个点或边只能配对一次,所有边必须配对,而点可以无需配对

这题有思维无码量还是比较友好的

现在我们有一张连通图,设它边数为$m$,点数为$n$,显然$m \ge n-1$

根据题意,一个点只能和一条边配对,自然的若在当前图中$m > n$,则是无解的

接下来进行分类讨论

$m=n$的情况下,有点类似**基环树**的感觉...思考和环有关的性质,若现在有一条环,每个点要和一条边进行匹配,不难发现匹配方案只有**两种**,因为一个点只和两条边相连嘛...对于基环上任意一个点的子树,因为**根节点必须与一条环上边匹配,所以其子树上任意一个节点只有子节点匹配其连向父节点的边一个选择**

$m=n-1$的情况下,借用上面的结论,每个子节点首先应该与其连向父节点的边匹配,而当前情况下我们**允许且只允许一个点不进行匹配**,那么方案数显然就是$n$了,可以画图理解

至于统计边数,就有很多种写法了,可以按照自己的思路写

//2019/8/7->Riko->AtNCU->luoguP3043
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>

namespace Rikopack {
    bool digit (int ch) { return (ch <= ‘9‘ and ch >= ‘0‘);}
    inline int in () {
    	int x = 0, ch = getchar(), base = 1;
    	while (!digit(ch)) {
    	    if (ch == ‘-‘) base = -1;
    	    ch = getchar();
    	}
    	while (digit(ch)) x = x*10+ch-‘0‘, ch = getchar();
    	return x*base;
    }
    template <typename T> inline void smax (T& x, T y) { if (x < y) x = y;}
    template <typename T> inline void smin (T& x, T y) { if (x > y) x = y;}
    void print (int x) { printf("debug:%d\n", x);}
    const int MAXINT = 2123456789;
    #define LL long long
    //Believing heart is your power
}
using namespace Rikopack;
using namespace std;

const int N = 101000, mod = 1e9+7;
int n, m, tmp, ans, Size, Edges;
int vis[N];
int nxt[N<<1], to[N<<1], bol[N], head[N], edgeind;
inline void add (int u, int v) {
	int i = ++edgeind;
	nxt[i] = head[u]; to[i] = v; head[u] = i;
}

void Getcir (int x, int fa) {
	vis[x] = true; Size++;
	for (int i = head[x]; i; i = nxt[i]) {
		int e = to[i];
		if (!bol[(i+1)/2]) {
			bol[(i+1)/2] = true;
			++Edges;
		}
		if (e == fa or vis[e]) continue;
		Getcir(e, x);
	}
}
void work (int x) {
	Edges = Size = tmp = 0;
	Getcir(x, 0);
	if (Edges == Size) tmp = 2;
	if (Edges == Size-1) tmp = Size;
}
void prepare () {
	n = in(); m = in();
	for (int i = 1; i <= m; ++i) {
		int u = in(), v = in();
		add(u, v); add(v, u);
	}
	ans = 1;
	for (int i = 1; i <= n; ++i) {
		if (!vis[i]) work(i);
		else continue;
		ans = ((LL)ans*tmp)%mod; 
		if (!ans) {
			puts("0"); return;
		}
	}
	printf("%d", ans);
}
int main () { prepare();}

  

【题解】 P3043 [USACO12JAN]牛联盟Bovine Alliance

标签:ios   ack   tin   usaco   写法   get   efi   and   ++   

原文地址:https://www.cnblogs.com/NHDR233/p/11330730.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!