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 题解

木棒游戏 文本编辑器 数据生成器 智破连环阵
  • qq_25471829
  • qq_25471829
  • 2015年05月29日 10:42
  • 523

【BZOJ 3614】 [Heoi2014]逻辑翻译|乱搞|辣鸡题目|不要入坑

po姐题解 《论一道题究竟如何出才能同时卡时间卡内存卡精度卡输入卡输出卡评测》 辣鸡题目 颓我精神 耗我时间!!! 把每个值带入假想的式子中 就变成啦 解方程 然后 然后 然后 然后 尼玛 输出这...
  • sxb_201
  • sxb_201
  • 2016年03月24日 10:42
  • 668

【BZOJ 3614】 [Heoi2014]逻辑翻译|乱搞|辣鸡题目|不要入坑

po姐题解 《论一道题究竟如何出才能同时卡时间卡内存卡精度卡输入卡输出卡评测》 辣鸡题目 颓我精神 耗我时间!!! 把每个值带入假想的式子中 就变成啦 解方程 然后 然后 然后 然后 尼玛 输出这...
  • sxb_201
  • sxb_201
  • 2016年03月24日 10:42
  • 668

毕业3年的程序员,怎么进BAT | 12000字揭秘阿里连环炮面试(附开发手册)

引言 本文作者左潇龙讲述了参加阿里社招面试的感悟以及技术学习的体会。作者本身是Java出身,关于主语言的问题是与Java相关,其它语言的同学可以选择性忽略,大家可以关注下学习方法,进行复用。...
  • l_215851356
  • l_215851356
  • 2017年11月21日 17:14
  • 194

九连环所有步骤

九连环所有步骤
  • nameofcsdn
  • nameofcsdn
  • 2017年01月01日 18:01
  • 1720

线阵CCD相机与面阵相机的区别

一、线阵相机 线阵CCD工业相机主要应用于工业、医疗、科研与安全领域的图象处理。在机器视觉领域中,线阵工业相机是一类特殊的视觉机器。与面阵工业相机相比,它的传感器只有一行感光元素,因此使高扫描频率和...
  • eileen163
  • eileen163
  • 2015年03月13日 16:33
  • 1129

磁阵应用系统简介

mount: 指挂载,即在linux操作系统中, 挂载是指将一个设备(通常是存储设备)挂接到一个已存在的目录上,对目录进行操作,就相当于对存储设备进行存储。 卷: 硬盘上的存储区域,驱动器使用一...
  • Genius_LG
  • Genius_LG
  • 2013年11月21日 17:32
  • 2046

拟阵理论和贪心算法浅析

前言对于一些NP-Hard问题,我们无法找到一个精确的求解方法。使用贪心思想采取贪心算法来求取近似解就成了常用的选择。很多算法名著对贪心算法都有很明确的讲解,这里对贪心算法摘取一下重点,然后我们要引出...
  • ChiXueZhiHun
  • ChiXueZhiHun
  • 2017年02月01日 14:47
  • 3078

怎样选择线阵相机,线阵镜头,线阵光源

关于线线相机、镜头、光源的选型,欢迎来电探讨线扫描系统的搭建与选型      随着机器视觉的大规模普及与工业流水线速度、精度的提高,线扫描系统越来越被视觉工程师和最终用户所认可。   首先,我对线...
  • caiqi1123
  • caiqi1123
  • 2014年04月25日 12:36
  • 2421

最大子阵和(百度2017秋招真题)

题目描述 给出一个n行m列的二维矩阵A[m,n],其每个元素的取值范围是[-1000,1000],其中1<=n<=100,1<=m<=100。求出p,q,r,s,满足条件1<=p<=...
  • zhengjihao
  • zhengjihao
  • 2017年06月26日 20:31
  • 263
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:NOI2003 智破连环阵
举报原因:
原因补充:

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