NOI2003 智破连环阵

原创 2016年06月01日 17:26:33


先甩两个论文:

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

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

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

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;
}






版权声明:本文为博主原创文章,未经博主允许【随意】转载。 举报

相关文章推荐

[题解]bzoj1507(NOI2003)Editor

Description Input 输入文件editor.in的第一行是指令条数t,以下是需要执行的t个操作。其中: 为了使输入文件便于阅读,Insert操作的字符串中可能会插入一些回车符,请...

BZOJ 1507 NOI2003 Editor Splay

题目大意: 1.将光标移动到某一位置 2.在光标后插入一段字符串 3.删除光标后的一段字符 4.输出光标后的一段字符 5.光标-- 6.光标++ 和1269很像的一道题,不过弱多了 几个问题需要注意...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

bzoj1509[NOI2003] 逃学的小孩

树的直径

NOI2003 矩阵游戏

题目大意:给定abcd和规则要求计算出一个大矩阵的最后一个数的值。 题目分析:两次快速幂,对于最后一位有两种处理方法:可以计算到最后一行的第一位然后快速幂计算出最后一位也可计算到下一行然后减d再/...

BZOJ 1507 [NOI2003]Editor

title: ‘BZOJ 1507 [NOI2003]Editor’ categories: BZOJ date: 2016-1-1 01:01:03 tags: [Splay]

[BZOJ1507]NOI2003 Editor|splay

Splay/块状链表裸题。。不过范围有点大,具体操作像维护数列样搞就是,输出的时候中序遍历一下那个区间的子树。。要注意的是读入的时候,最快的方法还是一个一个getchar,还有一个坑的地方就是scan...

【splay】BZOJ 1507:[NOI2003]Editor

BZOJ 1503 郁闷的出纳员DescriptionInput输入文件editor.in的第一行是指令条数t,以下是需要执行的t个操作。Output输出文件editor.out的每行依次对应输入文件...

BZOJ 1507 NOI 2003 Editor Splay

题目大意:维护一种数据结构,它可以: 1.移动光标 2.在光标之后插入一段字符串 3.删除光标之后的n个字符 4.输出光标之后的n个字符 5.移动光标 思路:Splay,没什么特别...

Noi-2003-木棒游戏

木棒游戏 【问题描述】 这是一个很古老的游戏。用木棒在桌上拼出一个不成立的等式,移动且只移动一根木棒使得等式成立。现在轮到你了。 【任务】 从文件读入一个式子(该式子肯定是一个不成立的等式)。...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)