sxb_201的博客

蒟蒻要刷题~~

NOI2003 智破连环阵


先甩两个论文:

这是楼教主的 用的 部分搜索 + 匹配   代码飞快比较神

算法合集之《浅谈部分搜索+高效算法在搜索问题中的应用

这是朱泽园的算是 面向数据编程..  用的 贪心搜索+各种剪枝(但用的剪枝还是比楼教主的少)

Zplhz_智破连环阵


我写的 朱泽园的算法 自己对着数据卡过去的 剪枝真是神啊

一个我感觉没啥用的剪枝可以直接把代码从 30 变成 80

详见代码注释


#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

int rank[101][101];
int lenth[101][101];
int ax[101],ay[101];
int bx[101],by[101];
int n,m,k;

void f(int x,int s,int t) 
{
	for(int i=s;i<=t;i++)
		lenth[i][x]=t-i+1;
}

int cmpx;
bool cmp(int a,int b)
{
	return lenth[cmpx][a]>lenth[cmpx][b];
}

bool can(int boom,int arms)
{
	return (ax[arms]-bx[boom])*(ax[arms]-bx[boom])+(ay[arms]-by[boom])*(ay[arms]-by[boom])<=k*k;
}

bool used[101];
int tail[101];
int ans=1000000000;
void dfs(int now,int cnt,int cnt3)
{
	if(cnt+tail[now]>=ans) return ;  // 神神神! 开始我没有加 tail数组 加上后跑得飞快 
	if(now>n)
	{
		ans=cnt;
		return ;
	}

	int kcnt=0;
	for(int i=1;i<=m&&kcnt!=3;i++)
	if(!used[rank[now][i]]&&lenth[now][rank[now][i]]!=0)
	{
		kcnt++;
		if(kcnt==3&&cnt3==0) break;
		used[rank[now][i]]=true;
		if(kcnt==3) dfs(now+lenth[now][rank[now][i]],cnt+1,cnt3-1);
		else dfs(now+lenth[now][rank[now][i]],cnt+1,cnt3);
		used[rank[now][i]]=false;
	}
}

int main()
{	
	cin >>n >>m >>k;
	for(int i=1;i<=n;i++) scanf("%d %d",&ax[i],&ay[i]);
	for(int i=1;i<=m;i++) scanf("%d %d",&bx[i],&by[i]);
	
	for(int i=1;i<=m;i++)
	{
		int s=1,t;
		while(s<=n)
		{
			while(s+1<=n&&can(i,s)==false) s++;
			if(can(i,s)==false) break;
			t=s;
			while(t+1<=n&&can(i,t+1)==true) t++;
			f(i,s,t);
			s=t+1;
		}
	}
	
	for(int i=1;i<=n;i++) 
	{
		cmpx=i;
		for(int j=1;j<=m;j++) rank[i][j]=j;
		sort(rank[i]+1,rank[i]+m+1,cmp);
	}
	
	for(int i=n;i>=1;i--)
		tail[i]=tail[i+lenth[i][rank[i][1]]]+1;
	
	dfs(1,0,1);  //此处面向数据 只给了一个 使用3 的机会 
	
	cout<<ans<<endl;
	
	return 0;
}


在加一个楼教主的论文代码 我没有格式化 自己边看边格式化吧 (我把第二部分的输出方案给注释掉了)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int maxm=100+2;
const int maxn=100+2;
int n,m,dist[maxm],MaxT[maxm][maxn];
bool reachable[maxm][maxn],*can[maxm][maxm];
/*
m=B 国武器数。
n=A 国炸弹数。
dist[i]=如果 A 国炸弹可以重复使用,炸掉 B 国武器 I~m 的最少使用炸弹数。
MaxT[s][i]=炸弹 I,从 S 开始炸,可以炸到的最大编号,
如果炸弹 I 炸不到 S,则 MaxT[I][S]=S-1。
reachable[i][j]=A国炸弹 i 是否可以炸到 B 国炸弹 j。
can[s][t][i]=表示 A 国炸弹 I 是否可以炸到 B 国武器 S,S+1..T-1,T。
*/
int answer,bestv[maxn];
/*
answer=最少需要的 A 国炸弹数。
bestv=记录取最优解 A 国炸弹的使用序列。
*/
int a[maxm],b[maxn];
bool vis[maxn],*g[maxm];
/*
a[i],b[i]用于匹配,分别记录左(右)第 i 个点的匹配边的另一个点的编号,如果没有匹配
则为 0。
vis[i]用于匹配和宽度优先搜索时判重。
g[i][j]=左边第 i 个点到右边第 j 个点是否有边。
*/
void init()
{
//读入数据并计算 reachable。
int x1[maxm],y1[maxm],x2[maxn],y2[maxn],i,j,R;
scanf("%d%d%d",&m,&n,&R);
for (i=1;i<=m;i++)
scanf("%d%d",&x1[i],&y1[i]);
for (i=1;i<=n;i++)
scanf("%d%d",&x2[i],&y2[i]);
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
reachable[i][j]=((x1[i]-x2[j])*(x1[i]-x2[j])+(y1[i]-y2[j])*(y1[i]
-y2[j])<=R*R);
}
void preprocess()
{
//初始化,计算 can,MaxT。
int s,t,i;
for (i=1;i<=m;i++)
g[i]=new bool[maxn];
for (s=1;s<=m;s++)
for (t=s;t<=m;t++)
can[s][t]=new bool[maxn];
for (s=1;s<=m;s++)
{
for (i=1;i<=n;i++)
can[s][s][i]=reachable[s][i];
for (t=s+1;t<=m;t++)
for (i=1;i<=n;i++)
can[s][t][i]=can[s][t-1][i] && reachable[t][i];
for (i=1;i<=n;i++)
{
MaxT[s][i]=s-1;
for (t=s;t<=m;t++)
if (can[s][t][i])
MaxT[s][i]=t;
}
}
//计算 dist
dist[m+1]=0;
for (s=m;s>=1;s--)
{
t=s-1;
for (i=1;i<=n;i++)
if (MaxT[s][i]>t)
t=MaxT[s][i];
dist[s]=1+dist[t+1];
}
}
bool find(int v)
{
//匈牙利算法找可增广路。
for (int i=1;i<=n;i++)
if (g[v][i] && !vis[i])
{
vis[i]=true;
if (b[i]==0 || find(b[i]))
{
a[v]=i;
b[i]=v;
return true;
}
}
return false;
}
void search(int used,int s)
{
//状态:已经使用了 used 个 A 国炸弹,编号在 s 之前的 B 国武器都已经炸毁。
if (used+dist[s]>=answer)//优化一:最优性剪枝
return;
if (s==m+1)
{
//如果 B 国武器已经全部炸毁,更新最优解,回溯。
answer=used;
memcpy(bestv,a,sizeof(a));
return;
}
int t,maxL,tempa[maxm],tempb[maxn],op,cl,queue[maxn],k,i;
//宽度优先搜索计算出下一个划分的最大长度 maxL
memset(vis,false,sizeof(vis));
maxL=s-1;
op=cl=0;
for (i=1;i<=n;i++)
if (b[i]==0)
{
vis[i]=true;
queue[++op]=i;
}
while (cl<op)
{
k=queue[++cl];
if (MaxT[s][k]>maxL)
maxL=MaxT[s][k];
for (i=1;i<=used;i++)
if (g[i][k] && !vis[a[i]])
{
vis[a[i]]=true;
queue[++op]=a[i];
}
}
if (maxL==s-1)
return;
used++;
memcpy(tempa,a,sizeof(a));
memcpy(tempb,b,sizeof(b));
memset(vis,false,sizeof(vis));
g[used]=can[s][maxL];
//扩展交错路。
find(used);
//从大到小枚举下一段的长度。
for (t=maxL;t>=s;t--)
{
g[used]=can[s][t];
search(used,t+1);
}
memcpy(a,tempa,sizeof(a));
memcpy(b,tempb,sizeof(b));
}
void out()
{
//输出结果。
printf("%d\n",answer);
/*for (int i=1;i<=answer;i++)
printf("%d ",bestv[i]);
printf("\n");*/
}
int main()
{
//freopen("zplhz10.in","r",stdin);
//freopen("zplhz10.out","w",stdout);
init();
preprocess();
answer=1000000000;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
search(0,1);
out();
return 0;
}






阅读更多
版权声明:本文为博主原创文章,未经博主允许【随意】转载。 https://blog.csdn.net/sxb_201/article/details/51557505
个人分类: 下午
想对作者说点什么? 我来说一句

深搜专题

深搜专题

Umbrella__ Umbrella__

2017-10-12 10:46:59

阅读数:141

霆智X8II存储阵W8系列产品资料

2012年12月22日 274KB 下载

没有更多推荐了,返回首页

不良信息举报

NOI2003 智破连环阵

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭