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(0≤N≤9),M(0≤M≤N∗N) , 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.
For each test case, the first line contains two integers N(0≤N≤9),M(0≤M≤N∗N) , 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)
*/