【HDU5727 2016 Multi-University Training Contest 1E】【状压DP做法 匈牙利匹配做法】Necklace n阳n阴排成环 特定相邻会抑郁 问最少抑郁阳球数

Necklace

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1872    Accepted Submission(s): 573


Problem Description
SJX has 2*N magic gems.   N  of them have Yin energy inside while others have Yang energy. SJX wants to make a necklace with these magic gems for his beloved BHB. To avoid making the necklace too Yin or too Yang, he must place these magic gems Yin after Yang and Yang after Yin, which means two adjacent gems must have different kind of energy. But he finds that some gems with Yang energy will become somber adjacent with some of the Yin gems and impact the value of the neckless. After trying multiple times, he finds out M rules of the gems. He wants to have a most valuable neckless which means the somber gems must be as less as possible. So he wonders how many gems with Yang energy will become somber if he make the necklace in the best way.
 

Input
  Multiple test cases.

  For each test case, the first line contains two integers   N(0N9),M(0MNN) , descripted as above.

  Then   M  lines followed, every line contains two integers   X,Y , indicates that magic gem   X  with Yang energy will become somber adjacent with the magic gem   Y with Yin energy.
 

Output
One line per case, an integer indicates that how many gem will become somber at least.
 

Sample Input
  
  
2 1 1 1 3 4 1 1 1 2 1 3 2 1
 

Sample Output
  
  
1 1
 

Author
HIT
 

Source

【HDU5727 2016 Multi-University Training Contest 1E】【状压DP做法】Necklace n阳n阴排成环 特定相邻会抑郁 问最少抑郁阳球数

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int n, m;
bool a[18][18];
int f[1 << 17][17][2];	//我们要记录之前那个
int one[1 << 18];
int main()
{
	for (int i = 0; i < (1 << 18); ++i)
	{
		int x = i;
		while (x)one[i] += x & 1, x >>= 1;
	}
	while (~scanf("%d%d", &n, &m))
	{
		MS(a, 0);
		for (int i = 0; i < m; ++i)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			--x; --y; y += n;
			a[x][y] = a[y][x] = 1;
		}
		if (n == 0) { puts("0"); continue; }
		if (n == 1) { printf("%d\n", a[0][1]); continue; }
		int nn = n + n - 1;
		int top = (1 << nn) - 1;
		//第一个球我们认为放置了nn号球(阴球)
		MS(f, 63); f[0][0][0] = 0;
		//枚举选球状态
		for (int i = 0; i <= top; ++i)
		{
			if (one[i] & 1)//如果此时为奇数个1,那么我们需要放阴球
			{
				for (int k = 0; k < n; ++k)if (i >> k & 1)//枚举之前那个阳球
				{
					for (int j = n; j < nn; ++j)if (~i >> j & 1)//枚举现在这个阴球
					{
						gmin(f[i | 1 << j][j][0], f[i][k][1]);//之前阳球抑郁的
						gmin(f[i | 1 << j][j][0], f[i][k][0] + a[k][j]);//之前阳球不抑郁
					}
				}
			}
			else//如果此时为偶数个1,那么我们需要放阳球
			{
				if (i == 0)
				{
					for (int j = 0; j < n; ++j)
					{
						gmin(f[1 << j][j][a[nn][j]], a[nn][j]);
					}
				}
				else for (int k = n; k < nn; ++k)if(i >> k & 1)//枚举之前那个阴球
				{
					for (int j = 0; j < n; ++j)if (~i >> j & 1)//枚举现在这个阳球
					{
						gmin(f[i | 1 << j][j][a[k][j]], f[i][k][0] + a[k][j]);
					}
				}
			}
		}
		int ans = 1e9;
		for (int j = 0; j < n; ++j)//枚举最后一个阳球
		{
			gmin(ans, f[top][j][1]);
			gmin(ans, f[top][j][0] + a[j][nn]);
		}
		printf("%d\n", ans);
	}
	return 0;
}
/*
【题意】
有n个阴球和n个阳球。(n<=9)
我们把它们间隔着摆成一个环。
然而,存在m个关系(x,y),如果阳球x与阴球y放在相邻的位置,阳球x就会抑郁。
问你最优摆放方法,使得尽可能少的阳球抑郁。

【类型】
状压DP or 二分图匹配

【分析】
这题,我们可以很简单地想到状态DP的做法——
类似于旅行商问题
[已有状态][最后一个点]
然后转移的时候枚举下一个点并进行转移。
复杂度为O(2^n * n * n)

特别的,我们需要记录最后一个球是阳球的条件下,该球是否抑郁,以避免做重复的权值更新。
这样子,这道题就做完啦。

不过这题,还存在二分图匹配做法——

【时间复杂度&&优化】
O(2^n * n * n)

*/

【HDU5727 2016 Multi-University Training Contest 1E】【匈牙利匹配做法】Necklace n阳n阴排成环 特定相邻会抑郁 问最少抑郁阳球数

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int n, m;
int p[11];
bool a[11][11];
vector<int>b[11];
int match[11];
bool vis[11];
bool find(int x)
{
	vis[x] = 1;
	for (int i = b[x].size() - 1; ~i; --i)
	{
		int y = b[x][i];
		if (!match[y])
		{
			match[y] = x;
			return 1;
		}
	}
	for (int i = b[x].size() - 1; ~i; --i)
	{
		int y = b[x][i];
		if (!vis[match[y]] && find(match[y]))
		{
			match[y] = x;
			return 1;
		}
	}
	return 0;
}
int hungary()
{
	int ret = 0;
	MS(match, 0);
	for (int i = 1; i <= n; ++i)
	{
		MS(vis, 0);
		if (find(i))++ret;
	}
	return ret;
}
int main()
{
	while (~scanf("%d%d", &n, &m))
	{
		MS(a, 0);
		for (int i = 0; i < m; ++i)
		{
			int x, y;
			scanf("%d%d", &x, &y);//yang && yin
			a[x][y] = 1;
		}
		if (n == 0) { puts("0"); continue; }
		if (n == 1) { printf("%d\n", a[1][1]); continue; }
		int ans = 10;
		p[1] = p[n + 1] = 1;
		for (int i = 2; i <= n; ++i)p[i] = i;
		do
		{
			for (int i = 1; i <= n; ++i)
			{
				b[i].clear();
				for (int j = 1; j <= n; ++j)
				{
					//不产生抑郁
					if (!a[i][p[j]] && !a[i][p[j + 1]])
					{
						b[i].push_back(j);
					}
				}
			}
			gmin(ans, n - hungary());
		} while (next_permutation(p + 2, p + n + 1));
		printf("%d\n", ans);
	}
	return 0;
}
/*
【题意】
有n个阴球和n个阳球。(n<=9)
我们把它们间隔着摆成一个环。
然而,存在m个关系(x,y),如果阳球x与阴球y放在相邻的位置,阳球x就会抑郁。
问你最优摆放方法,使得尽可能少的阳球抑郁。

【类型】
状压DP or 二分图匹配

【分析】
这题,我们可以很简单地想到状态DP的做法——
类似于旅行商问题
[已有状态][最后一个点]
然后转移的时候枚举下一个点并进行转移。
复杂度为O(2^n * n * n)

特别的,我们需要记录最后一个球是阳球的条件下,该球是否抑郁,以避免做重复的权值更新。
这样子,这道题就做完啦。

不过这题,还存在二分图匹配做法——
不过,一般的二分图匹配,每个节点最多只能有一个匹配点。
这道题可能有2个匹配点了。那我们要如何做?

我们可以先暴力全排列枚举阴球的位置,
然后对于每个阳球,就知道,它放在哪些位置,会使得答案+1.
这样我们做二分图匹配即可。
复杂度为O((n-1)! * n^3)

【时间复杂度&&优化】
O(2^n * n * n) => O((n-1)! * n^3)

*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值