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






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

相关文章推荐

NOI 2003 题解

木棒游戏 文本编辑器 数据生成器 智破连环阵

bzoj1508: [NOI2003]Game

传送门 Claris代码风格实在是不忍直视。 直接爆枚是单个数字上修改还是从一个数字移到另一个数字。 只是读入输出炒鸡麻烦。#include #include #include #include...

【21.00%】【vijos P1018】智破连环阵

描述 B国在耗资百亿元之后终于研究出了新式武器——连环阵(Zenith Protected Linked Hybrid Zone)。传说中,连环阵是一种永不停滞的自发性智能武器。但经过A国间谍的侦察...

浅谈部分搜索+高效算法在搜索问题中的应用 by 楼天城

浅谈部分搜索+高效算法在搜索问题中的应用 浙江省杭州第十四中学 楼天城 摘要: 本文从有位置限制的匹配问题的搜索谈起,通过对题目Milk Bottle Data的 分析,提出了深度优先搜索的一...
  • mbxc816
  • mbxc816
  • 2012年01月11日 01:30
  • 3732

C++ String類的研究1: append 方法

1.append方法: 在指定string尾部添加字串。 append方法的返回的结果为新string的引用。 常用的有6種重載: a. basic_string &append(const b...
  • ffjbq
  • ffjbq
  • 2012年05月28日 19:53
  • 3682

NOI2003试题day1

  • 2015年08月07日 13:59
  • 62KB
  • 下载

[题解]bzoj1507(NOI2003)Editor

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

BZOJ 1507 NOI2003 Editor Splay

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

bzoj1509[NOI2003] 逃学的小孩

树的直径

NOI2003 矩阵游戏

题目大意:给定abcd和规则要求计算出一个大矩阵的最后一个数的值。 题目分析:两次快速幂,对于最后一位有两种处理方法:可以计算到最后一行的第一位然后快速幂计算出最后一位也可计算到下一行然后减d再/...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:NOI2003 智破连环阵
举报原因:
原因补充:

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