告诉你若干个(<=100)武器的花费以及武器能消灭的怪物编号,问消灭所有怪物(<=100)的最小花费。。。当然每个武器可以无限次使用,不然这题就太水了╮(╯▽╰)╭

这题当时比赛的时候连题都还没看就结束了。。。。赛后一看,果断是重复覆盖。。。

不过之后一直没敲。。。然后今天算是补回来吧,同时也把好久以前学的DLX复习一下。。。

DLX的话,双向十字链表。。。具体的话,百度Google什么的dancing links。。。

一开始敲的时候还是挺顺利的,因为之前做过几次重复覆盖都是直接拿精确覆盖的模板来改。。。差不多的,不过重复覆盖就删列,代码好像还少几行呢。。。不过有时调一会有时wa上一两发。。。又鉴于最近好像好多重复覆盖的题。。。就好像spfa一样频繁出现=。=个人感觉不科学。。。

而且之前那个精确覆盖的模板实在是无法直视,太挫了写得╮(╯▽╰)╭

重点来了~~~代码写好了,可是不AC╮(╯▽╰)╭太可恶了。。。。让JM帮忙看代码。。。于是苦逼地一直找bug。。。。

经过一小时吧大概的奋斗。。。JM发现。。。一个非常好笑的呵呵的亮点。。。。memset(vis,false,sizeof(false));。。。笑死我了。。。还好这是平时随便敲。。。

然后就AC了~~~

复杂度。。不知道怎么算DLX的复杂度哎~~~求高手教,或者说一般N,M多少可以~~

总结就是,打代码要仔细。。。。总之不要犯这种逗比错误。。。。真正比赛的时候就笑不出来了~~~啦啦啦~~~谢谢JM~~~

 #include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <set>
using namespace std; #define ll long long
#define eps 1e-8
#define mod 21092013 #define inf 0x3f3f3f3f
#define maxr 110
#define maxn (maxr*maxr)
int n,m;
int L[maxn],R[maxn],U[maxn],D[maxn],cnt;
int row[maxn],col[maxn];
int N[maxr],use[maxr],head[maxr];
void init(){
memset(head,-,sizeof(head));
memset(N,,sizeof(N));
for(int i=;i<=m;++i){
L[i]=i-,R[i]=i+;
U[i]=D[i]=i;
row[i]=,col[i]=i;
}
L[]=m,R[m]=;
cnt=m;
}
void remove(int x){// 删除列
for(int i=D[x];i!=x;i=D[i])
L[R[i]]=L[i],R[L[i]]=R[i];
}
void resume(int x){// 恢复列
for(int i=D[x];i!=x;i=D[i])
L[R[i]]=R[L[i]]=i;
}
int low(){
int mi=maxr,idx=;
for(int i=R[];i;i=R[i])if(N[i]<mi)mi=N[i],idx=i;
return idx;
}
void link(int r,int c){
++N[c],++cnt;
row[cnt]=r,col[cnt]=c;
U[cnt]=U[c],D[cnt]=c;
U[D[cnt]]=D[U[cnt]]=cnt;
if(head[r]==-)
head[r]=L[cnt]=R[cnt]=cnt;
else {
L[cnt]=L[head[r]];
R[cnt]=head[r];
L[R[cnt]]=R[L[cnt]]=cnt;
}
}
int cost[maxr];
int ans;
void dance(int dep,int val){
if(R[]==){
ans = min(ans,val);
return ;
}
int c=low();
if(c==||val>=ans)return ;
for(int i=D[c];i!=c;i=D[i]){
use[dep]=i;
remove(i);
for(int j=R[i];j!=i;j=R[j])remove(j);
dance(dep+,val+cost[row[i]]);
for(int j=L[i];j!=i;j=L[j])resume(j);
resume(i);
}
} int main(){
while(~scanf("%d%d",&m,&n)){
init();
bool vis[maxr];
memset(vis,false,sizeof(vis));
ans=;
for(int i=;i<=n;++i){
int tmp,tmp2;
scanf("%d%d",cost+i,&tmp);
ans+=cost[i];
for(int j=;j<tmp;++j){
scanf("%d",&tmp2);
vis[tmp2]=true;
link(i,tmp2);
}
}
for(int i=;i<=m;++i)if(vis[i]==false){vis[]=false;break;}
if(vis[]==false){puts("-1");continue;}
dance(,);
printf("%d\n",ans);
}
return ;
}

Note: 之后想起在cf上有一题类似的,当时用DLX重复覆盖超时了,要DP,然后再去试一下。。。

结果发现有一些数据会卡掉这份代码

在这里征求高手解答。。。。这种数据要怎么过。。。

我的想法是预处理weapon[i]能否完全代替weapon[j]或weapon[j]+weapon[k]...不过万一他要weapon[i]+weapon[j]才能完全代替weapon[k]+weapon[l]呢...好乱...

求高手解答....

 void data(){
freopen("in.txt","w",stdout);
puts("33 99");
for(int i=;i<;++i)
if(i<)printf("%d %d %d\n",,,i%+);
else if(i<)printf("%d %d %d %d\n",,,i%+,(i+)%+);
else printf("%d %d %d %d %d\n",,,i%+,(i+)%+,(i+)%+);
}

参考了网上http://blog.sina.com.cn/s/blog_51cea4040100gwpv.html的剪枝优化。。。果然可以了。。。。可以跑出以上这种data了。。而且在fzu上的时间也从400+ms变成200+ms..排到第一了...有收获的感觉就是不错..这个剪枝感觉不错,好感动。。。泪牛满面,就是,当前价值+下界(不是下确界)>=best。。thank JM...

 #include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <set>
using namespace std; #define ll long long
#define eps 1e-8
#define mod 21092013 #define inf 0x3f3f3f3f
#define maxr 110
#define maxn (maxr*maxr)
int n,m;
int L[maxn],R[maxn],U[maxn],D[maxn],cnt;
int row[maxn],col[maxn];
int N[maxr],use[maxr],head[maxr];
void init(){
memset(head,-,sizeof(head));
memset(N,,sizeof(N));
for(int i=;i<=m;++i){
L[i]=i-,R[i]=i+;
U[i]=D[i]=i;
row[i]=,col[i]=i;
}
L[]=m,R[m]=;
cnt=m;
}
void remove(int x){// 删除列
for(int i=D[x];i!=x;i=D[i])
L[R[i]]=L[i],R[L[i]]=R[i];
}
void resume(int x){// 恢复列
for(int i=D[x];i!=x;i=D[i])
L[R[i]]=R[L[i]]=i;
}
int low(){
int mi=maxr,idx=;
for(int i=R[];i;i=R[i])if(N[i]<mi)mi=N[i],idx=i;
return idx;
}
void link(int r,int c){
++N[c],++cnt;
row[cnt]=r,col[cnt]=c;
U[cnt]=U[c],D[cnt]=c;
U[D[cnt]]=D[U[cnt]]=cnt;
if(head[r]==-)
head[r]=L[cnt]=R[cnt]=cnt;
else {
L[cnt]=L[head[r]];
R[cnt]=head[r];
L[R[cnt]]=R[L[cnt]]=cnt;
}
}
int cost[maxr];
int best;
int micost[maxr];
int cost2(){// lower_bound
int ret=;
bool del[maxn];
memset(del,false,sizeof(del));
for(int c=R[];c;c=R[c]){
if(!del[c]){
del[c]=true;
ret+=micost[c];
for(int i=D[c];i!=c;i=D[i])
for(int j=R[i];j!=i;j=R[j])
del[col[j]]=true;
}
}
return ret;
}
void dance(int dep,int val){
if(R[]==){
best = min(best,val);
return ;
}
int c=low();
if(c==||val>=best)return ;
if(val+cost2()>=best)return ;// important!
for(int i=D[c];i!=c;i=D[i]){
use[dep]=i;
remove(i);
for(int j=R[i];j!=i;j=R[j])remove(j);
dance(dep+,val+cost[row[i]]);
for(int j=L[i];j!=i;j=L[j])resume(j);
resume(i);
}
} int main(){
//void data();data();return 0;
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&m,&n)){
init();
memset(micost,0x3f,sizeof(micost));
best=;
for(int i=;i<=n;++i){
int tmp,tmp2;
scanf("%d%d",cost+i,&tmp);
best+=cost[i];
for(int j=;j<tmp;++j){
scanf("%d",&tmp2);
link(i,tmp2);
micost[tmp2]=min(micost[tmp2],cost[i]);
}
}
for(int i=;i<=m;++i)if(!N[i]){N[]=;break;}
if(!N[]){puts("-1");continue;}
dance(,);
printf("%d\n",best);
}
return ;
}
void data(){
freopen("in.txt","w",stdout);
puts("20 100");
for(int i=;i<;++i)
printf("%d %d %d\n",,,i%+);
}

想着经过这样的优化,大概之前cf那题应该可以过吧(当时是TLE 42,然后用DP过的),改了一下,SUBMIT,AC。。。超级感动的说。。。虽然比DP的要慢,但毕竟是搜索算法嘛。。。很不错了。。。DLX 600+ms(只有第60个case>15ms....别的case都<=15ms); DP 200+ms(相对较多100+ms,200+ms)。。。这篇应该不用再编辑了吧╮(╯▽╰)╭有错漏的话请观客提出=。=本人目前处于自嗨状态

 #include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <set>
using namespace std; #define ll long long
#define eps 1e-8
#define mod 21092013 #define inf 0x3f3f3f3f
#define maxr 110
#define maxn (maxr*maxr)
int n,m;
int L[maxn],R[maxn],U[maxn],D[maxn],cnt;
int row[maxn],col[maxn];
int N[maxr],use[maxr],head[maxr];
int monitor[maxr];
int B;
void init(){
memset(head,-,sizeof(head));
memset(N,,sizeof(N));
for(int i=;i<=m;++i){
L[i]=i-,R[i]=i+;
U[i]=D[i]=i;
row[i]=,col[i]=i;
}
L[]=m,R[m]=;
cnt=m;
}
void remove(int x){// 删除列
for(int i=D[x];i!=x;i=D[i])
L[R[i]]=L[i],R[L[i]]=R[i];
}
void resume(int x){// 恢复列
for(int i=D[x];i!=x;i=D[i])
L[R[i]]=R[L[i]]=i;
}
int low(){
int mi=maxr,idx=;
for(int i=R[];i;i=R[i])if(N[i]<mi)mi=N[i],idx=i;
return idx;
}
void link(int r,int c){
++N[c],++cnt;
row[cnt]=r,col[cnt]=c;
U[cnt]=U[c],D[cnt]=c;
U[D[cnt]]=D[U[cnt]]=cnt;
if(head[r]==-)
head[r]=L[cnt]=R[cnt]=cnt;
else {
L[cnt]=L[head[r]];
R[cnt]=head[r];
L[R[cnt]]=R[L[cnt]]=cnt;
}
}
int cost[maxr];
ll best;
int micost[maxr];
ll cost2(){// lower_bound
ll ret=;
bool del[maxn];
memset(del,false,sizeof(del));
for(int c=R[];c;c=R[c]){
if(!del[c]){
del[c]=true;
ret+=micost[c];
for(int i=D[c];i!=c;i=D[i])
for(int j=R[i];j!=i;j=R[j])
del[col[j]]=true;
}
}
return ret;
}
void dance(int dep,ll val,int mak){
if(R[]==){
best = min(best,val+(ll)mak*B);
return ;
}
int c=low();
if(c==||val+(ll)mak*B>=best)return ;
if(val+(ll)mak*B+cost2()>=best)return ;// important!
for(int i=D[c];i!=c;i=D[i]){
use[dep]=i;
remove(i);
for(int j=R[i];j!=i;j=R[j])remove(j);
dance(dep+,val+cost[row[i]],max(mak,monitor[row[i]]));
for(int j=L[i];j!=i;j=L[j])resume(j);
resume(i);
}
} int main(){
//void data();data();return 0;
//freopen("in.txt","r",stdin);
while(~scanf("%d%d%d",&n,&m,&B)){
init();
memset(micost,0x3f,sizeof(micost));
best=;int mam=;
for(int i=;i<=n;++i){
int tmp,tmp2;
scanf("%d%d%d",cost+i,monitor+i,&tmp);
best+=cost[i];
mam=max(mam,monitor[i]);
for(int j=;j<tmp;++j){
scanf("%d",&tmp2);
link(i,tmp2);
micost[tmp2]=min(micost[tmp2],cost[i]);
}
}
best+=(ll)mam*B;
for(int i=;i<=m;++i)if(!N[i]){N[]=;break;}
if(!N[]){puts("-1");continue;}
dance(,,);
printf("%I64d\n",best);
}
return ;
}
void data(){
freopen("in.txt","w",stdout);
puts("20 100");
for(int i=;i<;++i)
printf("%d %d %d\n",,,i%+);
}

附上DP代码吧

 #include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std; #define ll long long
//#define inf 0x3f3f3f3f
#define inf (1ll<<60)
#define maxn 110
#define mod 1000000007
#define eps 1e-8 struct node{
int x,k,st;
}p[maxn];
bool cmp(node a,node b){return a.k<b.k;}
ll dp[<<];
int main(){
int n,m,b,mm,tmp;
while(~scanf("%d%d%d",&n,&m,&b)){
for(int i=;i<n;++i){
scanf("%d%d%d",&p[i].x,&p[i].k,&mm);
p[i].st=;
while(mm--){
scanf("%d",&tmp);
p[i].st+=(<<(tmp-));
}
}
ll ans=inf;
sort(p,p+n,cmp);
for(int j=(<<m)-;j;--j)dp[j]=inf;
dp[]=;
for(int i=;i<n;++i){
for(int j=(<<m)-;j>=;--j)
dp[j|p[i].st] = min(dp[j|p[i].st], dp[j]+p[i].x);
ans = min(ans,dp[(<<m)-]+(ll)p[i].k*b);
}
if(ans==inf)puts("-1");
else printf("%I64d\n",ans);
}
return ;
}

FZU 2165 v11(最小重复覆盖)+ codeforces 417D Cunning Gena的更多相关文章

  1. Codeforces 417D Cunning Gena(状态压缩dp)

    题目链接:Codeforces 417D Cunning Gena 题目大意:n个小伙伴.m道题目,每一个监视器b花费,给出n个小伙伴的佣金,所须要的监视器数,以及能够完毕的题目序号. 注意,这里仅仅 ...

  2. codeforces 417D. Cunning Gena 状压dp

    题目链接 D. Cunning Gena time limit per test 1 second memory limit per test 256 megabytes input standard ...

  3. FZU 1686 神龙的难题 (重复覆盖)

    Problem 1686 神龙的难题 Accept: 397    Submit: 1258Time Limit: 1000 mSec    Memory Limit : 32768 KB  Prob ...

  4. (简单) FZU 1686 神龙的难题 , DLX+可重复覆盖。

    Description 这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就 ...

  5. FZU2165 v11(带权的重复覆盖)

    题意:有n个boss,m种武器,每种武器选用的时候需要有一定的花费ci,然后这个武器可以消灭掉其中一些BOSS,问你消灭完所有的BOSS,需要的最少花费是多少. 当时比赛的时候,看到这题以为是什么网络 ...

  6. FZU Problem 1686 神龙的难题 重复覆盖

    题目链接 给出大矩形的长宽, 矩形里面有1,0两个值, 给出小矩形的长宽, 求用最少的小矩形覆盖所有的1. 重复覆盖的模板题. #include <iostream> #include & ...

  7. Codeforces 618D Hamiltonian Spanning Tree(树的最小路径覆盖)

    题意:给出一张完全图,所有的边的边权都是 y,现在给出图的一个生成树,将生成树上的边的边权改为 x,求一条距离最短的哈密顿路径. 先考虑x>=y的情况,那么应该尽量不走生成树上的边,如果生成树上 ...

  8. HDU 3957 Street Fighter (最小支配集 DLX 重复覆盖+精确覆盖 )

    DLX经典题型,被虐惨了…… 建一个2*N行3*N列的矩阵,行代表选择,列代表约束.前2*N列代表每个人的哪种状态,后N列保证每个人至多选一次. 显然对手可以被战胜多次(重复覆盖),每个角色至多选择一 ...

  9. DLX 舞蹈链 精确覆盖 与 重复覆盖

    精确覆盖问题:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 还有重复覆盖问题 dancing links 是 一种数据结构,用来优化搜索,不算是一种算法.(双向 ...

随机推荐

  1. 自定义列表dl的使用原因和场合

    为什么要使用自定义列表? dl和ol, ul的区别? 要正确理解dl的意图, 理解 dl的 "语义" ! 才能知道为什么要使用dl, 以及在什么时候/ 什么情况下使用 dl? dl ...

  2. ThinkPHP的四种URL模式 URL_MODEL

    ThinkPHP支持四种URL模式,可以通过设置URL_MODEL参数来定义,包括普通模式.PATHINFO.REWRITE和兼容模式. 普通模式 设置URL_MODEL 为0 采用传统的URL参数模 ...

  3. jelq

    初级 The Newbie Routine 5 minutes hot wrap 5 minutes manual stretch (ten 30-second stretches) 10 minut ...

  4. Maven工程中报 Missing artifact jdk.tools:jdk.tools:

    jdk.tools:jdk.tools是与JDK一起分发的一个JAR文件,可以如下方式加入到Maven项目中:<dependency>    <groupId>jdk.tool ...

  5. Ubuntu 14 编译安装 PHP 5.4.45 + Nginx 1.4.7 + MySQL 5.6.26 笔记

    Ubuntu 14 编译安装 PHP 5.4.45 + Nginx  1.8.0/1.4.7 + MySQL 5.6.26 笔记,主要是给自己的PC机安装,非生产环境! 一.下载必要的源码 1.1.下 ...

  6. 1.2 从 ACID 到 CAP/BASE

    1.事务 事务(Tranction)是指,由一系列对系统中数据进行访问与更新操作,所组成的一个逻辑执行单元.狭义上的事务是指数据库事务. 事务有四个特性. 原子性:原子性要求事务只允讲有两种状态,全部 ...

  7. 基于SSL协议的双向认证 - 双向认证 [3]

    1      SSL双向认证的实现 这里是基于SSL和Tomcat配置实现的,配置方法如下: 1.1    生成CA数字证书 首先需要配置OPENSSL环境变量. 我的OPENSSL配置文件路径是“D ...

  8. Codeforces 259 B - Little Pony and Sort by Shift

    题目链接:http://codeforces.com/contest/454/problem/B 解题报告:太渣了,这个模拟题最后跑大数据的时候挂了,最后还花了很久才过,用的最笨的方法,直接模拟,代码 ...

  9. 我对windows消息机制的理解(参考深入浅出MFC,欢迎批评指正!!)

    以消息为基础,以事件驱动之 程序的进行依靠外部消息来驱动,即:程序不断等待任何可能的输入,然后做判断,然后再做适当的处理. 消息输入:操作系统捕获,以消息形式进入程序.(操作系统通过其USERS模块中 ...

  10. Sqli-LABS通关笔录-14

    这一节让我学习到了 1.extractvalue函数(该函数用于对xml文件进行查询和修改,于此相关的还有一个叫“updatexml”函数) 语法:extractvalue(XML_document, ...