【USACO09NOV】灯Lights(DFS+二分)

这题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?能过就行。

猜你喜欢

转载自blog.csdn.net/WWWengine/article/details/82288962