这题N实在太小了,暴搜都可以得到很可观的分数,为了巩固搜索,就用DFS做了一下。BFS貌似也可做。
在搜索前需要把每个点的异或值求出来,这样就不用建边枚举边了。
首先每个灯最多被按一次;其次猜测需要按下的次数在10次以下。
于是方案1:迭代加深搜索。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN=36;
int N,lim,ans=40;
LL turn[MAXN],goal;
bool cmp(LL a,LL b) {return a>b;}
int dfs(int t,int step,LL state)
{
if(step>=ans) return 0;
if(state==goal)
{
ans=min(ans,step);
return 1;
}
if(step==lim)
return 0;
for(int i=t+1;i<=N;i++)
if(dfs(i,step+1,state^turn[i]))
return 1;
return 0;
}
int main()
{
int i,M,u,v;
cin>>N>>M;
goal=(1ll<<N)-1;
for(i=1;i<=M;i++)
{
cin>>u>>v;
turn[u]|=(1ll<<(v-1));
turn[v]|=(1ll<<(u-1));
}
for(i=1;i<=N;i++)
turn[i]|=(1ll<<(i-1));
sort(turn+1,turn+1+N,cmp);
for(lim=1;;lim++)
if(dfs(0,0,0))
break;
cout<<ans;
return 0;
}
洛谷上发现可以得到94分,有一个点答案是14。而这个算法写出来应该20分钟以内,算是赚了。或许还可以剪枝拿满分。
DFS满分做法:把N个节点划分成两部分,对一半搜索并记录在map里,另一半搜索时直接在map里查找即可。
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN=36;
int N,ans=40;
LL turn[MAXN],goal;
map<LL,int>mp;
void dfs1(int t,int step,LL state)
{
if(t>N/2)
{
if(mp[state]==0||mp[state]>step) mp[state]=step;
if(state==goal) ans=min(ans,step);
return;
}
dfs1(t+1,step+1,state^turn[t+1]);
dfs1(t+1,step,state);
}
void dfs2(int t,int step,LL state)
{
if(step>=ans) return;
if(t>N)
{
if(mp[goal^state]!=0) ans=min(ans,mp[goal^state]+step);
if(state==goal) ans=min(ans,step);
return;
}
dfs2(t+1,step+1,state^turn[t+1]);
dfs2(t+1,step,state);
}
int main()
{
int i,M,u,v;
cin>>N>>M;
goal=(1ll<<N)-1;
for(i=1;i<=M;i++)
{
cin>>u>>v;
turn[u]|=(1ll<<(v-1));
turn[v]|=(1ll<<(u-1));
}
for(i=1;i<=N;i++)
turn[i]|=(1ll<<(i-1));
dfs1(0,0,0);
dfs2(N/2+1,0,0);
cout<<ans;
return 0;
}
正解:高斯消元+一点点DFS?能过就行。