1021 Safe Fruit (35 分)
解题思路:
用纯DFS+剪枝可以剪到26分。。。最后两个点不这样估计是过不去了,最大团(最大独立集)问题的裸题。
原来的搜索方法:
顺序搜索,从0(位置)开始枚举每个点,先根据已有的集合判断这个点可不可以被选,如果这个点可以被挑选,则进行选、不选的两个状态搜索,如果不能,则直接进行不选的状态搜索。
尝试记忆化搜索,内存超限,失败。
(贪心可以过最后一个点,再拿3分)
学习Bron–Kerbosch算法之后的搜索优化:
- 转变思路,将题目没有列举出来的边视为相连边,列举出来的视为不相连的边。
- 倒序枚举每个点作为起始状态(即这个点必选),然后从这个点往后进行正常的最大团搜索(即新加的点必须与所有已选的点相连),就可以得到以这个点为起点往后进行搜索的最大团,同时我们不重置以往搜索到的最大团,就可以得到从i位置往后任何一个位置为起点的最大团(即后缀最大团),后缀最大团个数记为cnt[i]。
- 进行剪枝,在每次选新的点i的时候,因为是向后搜索,所有cnt[i]都会已经被计算过,因此我们判断cnt[i]+num即当前的理想最优情况(可能会更差,因为加入了前面的点,可能会冲突无法取到cnt[i])是否比max要小,如果cnt[i]+num<max,说明取了点i的理想最优情况下都不如我的已有答案要好,那显而易见直接return;
就是这样短短的优化,最后只需要200ms,可见还是剪了很多情况的,有点类似DP的思想
代码:
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define G 6.67430*1e-11
#define rd read()
#define pi 3.1415926535
using namespace std;
const ll mod = 1e9 + 7;
const int MAXN = 30000005;
const int MAX2 = 300005;
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch>'9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
ll fpow(ll a, ll b)
{
ll ans = 1;
while (b)
{
if (b & 1)ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
}
int fa1[1005], fa2[1005];
int find(int* fa, int r) { return fa[r] == r ? r : fa[r] = find(fa, fa[r]); }
void join(int* fa, int x, int y)
{
int fx = find(fa, x), fy = find(fa, y);
fa[fx] = fy;
}
#define int ll
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
int g[1000][1000];
int price[1000];
vector<int> con[1000];
bool cmp(int a, int b)
{
return con[a] < con[b] || (con[a] == con[b] && price[a] < price[b]);
}
vector<int> v, ans, tmp;
int enable[1000];
int cnt[1000];
int n, m, ma = 0, miprice = 1e9;
void dfs(int i, int num, int p)
{
for (int j = i + 1; j < m; j++)
{
if (cnt[j] + num < ma)return;
if (!g[v[i]][v[j]])
{
int f = 0;
for (auto p : tmp)
{
if (g[v[j]][p])
{
f = 1;
break;
}
}
if (!f)
{
tmp.push_back(v[j]);
dfs(j, num + 1, p + price[v[j]]);
tmp.pop_back();
}
}
}
if (num > ma || (num == ma && p < miprice))
{
ma = num;
ans = tmp;
miprice = p;
}
}
signed main()
{
n = rd, m = rd;
for (int i = 0; i < n; i++)
{
int a = rd, b = rd;
g[a][b] = g[b][a] = 1;
}
for (int i = 0; i < m; i++)
{
int a = rd, b = rd;
price[a] = b;
v.push_back(a);
}
for (int i = m - 1; i >= 0; i--)
{
tmp.push_back(v[i]);
dfs(i, 1, price[v[i]]);
cnt[i] = ans.size();
tmp.pop_back();
}
sort(ans.begin(), ans.end());
cout << ans.size() << endl;
int f = 1;
for (auto p : ans)
{
if (!f)cout << ' ';
printf("%03d", p);
f = 0;
}
cout << endl << miprice;
return 0;
}