写了一些没有具体算法的搜索题。
这种题目在离线赛中遇到可能会很难办了,
完全没有办法搞清楚最后能得多少分。
只能说是尽可能地剪枝并卡常,
然后祈祷能AC之类的。
某NOIP几乎不会有这种题,
不过可以用来写暴力(以及说不定就过了
附暴力踩标程一张:

T1 stick

分析

N≤65N\le65,并且没有什么可以高效求解的算法。
搜索不加剪枝的话会被卡成智障。
那加剪枝啊:
1. 可行性:当前的答案肯定要整除所有木棍的长度和。
2. 最优性:搜索答案升序,搜到即退出。
3. 最大限制:木棍降序排序,以满足最快得到结果。
4. 排除重复:如果当前木棍是组成新木棍的第一根木棍,则其不可行代表当前方案不可行。
5. 排除重复:如果许多根木棍一样长,使用它们的效果是一样的,如果用某根不可行,其他同样不可行。
6. 排除重复:如果当前木棍完成了一根完整木棍的组装,而之后不可行代表当前方案不可行。
7. 奇偶性:如果答案为奇数,检查每次至少需要多少根奇数的木棒,若过少则代表当前方案不可行。
然后大约要加这么多剪枝才能过掉这道题的鬼畜数据。

代码

普通的DFS。

#include<bits/stdc++.h>
using namespace std;#define Komachi is retarded
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)
#define M 104
#define Mx 3444
#define INF 0x3f3f3f3f
#define chkmax(a,b) a=max(a,b)void Rd(int &res){char c;res=0;while((c=getchar())<48);do res=(res<<3)+(res<<1)+(c^48);while((c=getchar())>47);
}int n,A[M],Num[4];
bool Vis[M];
bool Cmp(int a,int b){return a>b;}
bool DFS(int need,int sum,int l,int len){if(need==0)return 1;if(len&1 && Num[1]<need-1)return 0;REP(i,l,n){if(Vis[i] || (i && !Vis[i-1] && A[i]==A[i-1]))continue;if(sum+A[i]==len){Vis[i]=1;Num[A[i]&1]--;if(DFS(need-1,0,0,len))return 1;Vis[i]=0;Num[A[i]&1]++;return 0;}else if(sum+A[i]<len){Vis[i]=1;Num[A[i]&1]--;if(DFS(need,sum+A[i],i+1,len))return 1;Vis[i]=0;Num[A[i]&1]++;if(!sum)return 0;}}return 0;
}
int main(){while(1){Rd(n);if(!n)break;int Sum=0;memset(Num,0,sizeof(Num));REP(i,0,n){Rd(A[i]);Sum+=A[i];Num[A[i]&1]++;}sort(A,A+n,Cmp);REP(i,A[n-1],Sum+1){if(Sum%i)continue;memset(Vis,0,sizeof(Vis));if(DFS(Sum/i,0,0,i)){printf("%d\n",i);break;}}}return 0;
}

T2 buses

分析

根据某论文一大片的分析说明了某种写法的可行与另一种写法的不可行
大体来说即为先单确定路线的第一辆车,
搜索得到其第二辆车,再判断其可行性。
剪枝:
1. 可行性:一条线路必须可行(废话
2. 最优性:线路数大于当前答案时返回
3. 排除重复:如果两辆车到达时间相同,此时若某辆车是第一辆车,则之后的车只能成为第一辆车。
然后我们可以知道对车进行的搜索比对线路进行的搜索要优秀。
大约就是这样。

代码

#include<bits/stdc++.h>
using namespace std;#define Komachi is retarded
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)
#define M 304
#define INF 0x3f3f3f3f
#define chkmin(a,b) a=min(a,b)
#define chkmax(a,b) a=max(a,b)int n,A[M],Ans=17;
int L[M],R[M];
bool Vis[M],Use[M];
void DFS(int num,int x){if(num>=Ans)return;if(x==n){Ans=num;return;}if(Vis[x]){DFS(num,x+1);return;}if(x && Use[x-1] && A[x]==A[x-1]){Use[x]=1;L[num]=A[x],R[num]=-1;DFS(num+1,x+1);Use[x]=0;return;}REP(i,0,num){if(R[i]==-1 && A[x]!=L[i]){int Len=A[x]-L[i],Pos=A[x];REP(j,x,n)if(!Vis[j] && A[j]==Pos)Pos+=Len;if(Pos<A[n-1])continue;R[i]=A[x];Pos=R[i];REP(j,x,n)if(!Vis[j] && A[j]==Pos)Vis[j]=1,Pos+=Len;DFS(num,x+1);Pos-=Len;DREP(j,n-1,x-1)if(Vis[j] && A[j]==Pos)Vis[j]=0,Pos-=Len;R[i]=-1;}}Use[x]=1;L[num]=A[x],R[num]=-1;DFS(num+1,x+1);Use[x]=0;
}
int main(){scanf("%d",&n);REP(i,0,n)scanf("%d",&A[i]);sort(A,A+n);DFS(0,0);printf("%d\n",Ans);return 0;
}

T3 Betsy’s tour

求矩阵从左上角到左下角的且遍历完所有格子的方案数。
剪枝是很明显的,
所有未经过的格子均应至少相邻两个未经过的格子(除终点
即不走将剩余格子分为两个连通块的那种格子。
然而每次扫一遍全图判断是很慢的,
然后发现每次只会修改周围四个格子的相邻格子数,
于是判断改为单次的。
再加上上面那个剪枝的修改型判断方式就能过了。

代码

防止数组越界就修改一下矩阵的位置。

#include<bits/stdc++.h>
using namespace std;#define Komachi is retarded
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)
#define M 14
#define chkmin(a,b) a=min(a,b)
#define chkmax(a,b) a=max(a,b)int n,Sn;
int Ans;
bool Vis[M][M];
int Cnt[M][M];
int Xr[]={1,0,-1,0},Yr[]={0,1,0,-1};bool Check(int x,int y){return x>1 && y>1 && x<n && y<n;}void DFS(int x,int y,int t,int r){if(x==n-1 && y==2){Ans+=t==Sn;return;}int px,py,xp=x+Xr[r],yp=y+Yr[r],a1=(r+1)%4,a2=(r+3)%4,mst=0;if(Vis[xp][yp] && !Vis[x+Xr[a1]][y+Yr[a1]] && !Vis[x+Xr[a2]][y+Yr[a2]])return;if(Vis[xp+Xr[a1]][yp+Yr[a1]] && !Vis[xp][yp] && !Vis[x+Xr[a1]][y+Yr[a1]])return;if(Vis[xp+Xr[a2]][yp+Yr[a2]] && !Vis[xp][yp] && !Vis[x+Xr[a2]][y+Yr[a2]])return;REP(g,0,4){xp=x+Xr[g],yp=y+Yr[g];if(xp==n-1 && yp==2)continue;if(Check(xp,yp) && !Vis[xp][yp] && Cnt[xp][yp]==1)mst++;}if(mst>1)return;REP(g,0,4){xp=x+Xr[g],yp=y+Yr[g];if(!Check(xp,yp) || Vis[xp][yp])continue;if(mst && Cnt[xp][yp]!=1)continue;Vis[xp][yp]=1;REP(f,0,4){px=xp+Xr[f],py=yp+Yr[f];Cnt[px][py]--;}DFS(xp,yp,t+1,g);REP(f,0,4){px=xp+Xr[f],py=yp+Yr[f];Cnt[px][py]++;}Vis[xp][yp]=0;}
}
int main(){scanf("%d",&n);Sn=n*n;n+=2;REP(i,2,n) REP(j,2,n) REP(g,0,4)Cnt[i][j]+=Check(i+Xr[g],j+Yr[g]);Cnt[2][2]=0,Cnt[2][3]=Cnt[3][2]=2;Vis[2][2]=1;DFS(2,2,1,0);printf("%d\n",Ans);return 0;
}

T4 Backward Digit Sums

原题没有这么鬼畜的啊(n≤20n \le 20

分析

各项系数是杨辉三角,
然后普通的枚举全排列就妥当地爆炸。
然后稍微不普通一点的DFS仍然会爆炸。
然后据说最后的代码随便卡一下还是会爆炸。
剪枝:
1. 对当前已枚举位作状态压缩,预处理出其上下界用于可行性剪枝O(2n∗n)O(2^n*n)
2. 由于杨辉三角是对称的,题目又要求字典序最小,因此需要保证对称位上一直是左侧小于右侧。
3. 然后加上各种玄学常数优化就能卡过数据(比方说寻址代替运算
实际上效率还是挺高的。

代码

#include<bits/stdc++.h>
using namespace std;#define Komachi is retarded
#define REP(i,a,b) for(register int i=(a),i##_end_=(b);i<i##_end_;i++)
#define DREP(i,a,b) for(register int i=(a),i##_end_=(b);i>i##_end_;i--)
#define M 24
#define Mm 1144444int n,T,Use[M],P[M],V[M];
int C[M][M],With[M],Mid;
long long tim;
bool Vis[M],Find;
int Mn[Mm],Mx[Mm],Num[Mm],MxS;
int BNum[Mm];
void Init(){memset(Mn,0,sizeof(Mn));memset(Mx,0,sizeof(Mx));REP(i,0,1<<n){int x,k;x=k=0;REP(j,0,n)if(i&(1<<j))x++;else P[k++]=j+1;Num[i]=x;if(x==n)break;int l=x,r=n-1;k=0;while(l!=r){if(C[n-1][r]<=C[n-1][l]) V[k++]=C[n-1][r--];else V[k++]=C[n-1][l++];}V[k++]=C[n-1][l];REP(j,0,k)Mn[i]+=P[k-j-1]*V[j];REP(j,0,k)Mx[i]+=P[j]*V[j];}MxS=(1<<n)-1;REP(i,0,n)BNum[1<<i]=i+1;REP(i,Mid,n)With[i]=n-i-1;
}
void DFS(int S,int Sum){if(Sum+Mx[S]<T || Sum+Mn[S]>T)return;tim++;if(S==MxS){if(Sum==T){REP(i,0,n)printf("%d ",Use[i]);puts("");Find=1;}return;}if(Num[S]<Mid){for(register int i=MxS^S,j=i&-i;i;i^=i&-i,j=i&-i){Use[Num[S]]=BNum[j];DFS(S|j,Sum+BNum[j]*C[n-1][Num[S]]);if(Find)return;}}else{for(register int i=MxS^S,j=i&-i;i;i^=i&-i,j=i&-i){if(BNum[j]<Use[With[Num[S]]])continue;Use[Num[S]]=BNum[j];DFS(S|j,Sum+BNum[j]*C[n-1][Num[S]]);if(Find)return;}}
}int main(){REP(i,0,M-1){C[i][0]=1;REP(j,1,i+1)C[i][j]=C[i-1][j-1]+C[i-1][j];}scanf("%d%d",&n,&T);Mid=n&1?(n>>1)+1:(n>>1);Init();Find=0;DFS(0,0);return 0;
}

T5 ZPLHZ

分析

使用二分图匹配来进行判断的搜索,比较巧妙。
每次枚举当前区间加入到二分图中,查看其是否能够和所有炸弹匹配。
1. 降序枚举区间长度来加速到达近似解
2. 用DP解得炸弹重复使用的近似解来进行最优化剪枝。
3. 每次只对当前区间匹配,然后还原现场。

代码

#include<bits/stdc++.h>
using namespace std;#define Komachi is retarded
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)
#define chkmin(a,b) a=min(a,b)
#define chkmax(a,b) a=max(a,b)#define M 104
void Rd(int &res){char c;res=0;while((c=getchar())<48);do res=(res<<3)+(res<<1)+(c^48);while((c=getchar())>47);
}
int n,m,k,x[M],y[M],u[M],v[M];
bool C[M][M][M];
int Dist[M];
int Ans;
int UL[M],UR[M];
int Re[M];
bool Vis[M];bool Find(int l,int r,int x){REP(i,0,m) if(!Vis[i] && C[i][l][r]){Vis[i]=1;if(Re[i]==-1 || Find(UL[Re[i]],UR[Re[i]],Re[i])){Re[i]=x;return 1;}Vis[i]=0;}return 0;
}
bool Check(int num){memset(Vis,0,sizeof(Vis));return Find(UL[num],UR[num],num);
}
void DFS(int pos,int num){if(pos==n){chkmin(Ans,num);return;}if(Dist[pos+1]+num>=Ans)return;UL[num]=pos;DREP(i,n-1,pos-1){UR[num]=i;if(Check(num)){DFS(i+1,num+1);REP(i,0,m)if(Re[i]==num){Re[i]=-1;break;}}}
}
inline int Sqr(int x){return x*x;
}
int main(){Rd(n),Rd(m),Rd(k);k*=k;REP(i,0,n)Rd(x[i]),Rd(y[i]);REP(i,0,m)Rd(u[i]),Rd(v[i]);REP(i,0,m)REP(j,0,n)C[i][j][j]=(Sqr(x[j]-u[i])+Sqr(y[j]-v[i])<=k);REP(i,0,m)REP(j,0,n)REP(k,j+1,n) C[i][j][k]=C[i][j][k-1]&&C[i][k][k];memset(Dist,63,sizeof(Dist));Dist[n]=0;DREP(i,n-1,-1) REP(j,i,n) REP(k,0,m) if(C[k][i][j]) chkmin(Dist[i],Dist[j+1]+1);memset(Re,-1,sizeof(Re));Ans=m;DFS(0,0);printf("%d\n",Ans);return 0;
}

DFS Cut twigs相关推荐

  1. LeetCode 698.Partition_to_k_equal_subsets. Three different solutions: DFS, DP, DP topdown + DFS

    Problem Partition a set A=(a1,a2,...,an)A=(a_1,a_2,...,a_n)A=(a1​,a2​,...,an​) to kkk disjointed sub ...

  2. CF982 C Cut 'em all!【树/DFS/思维】

    [链接]:CF982C [题意]:有一颗树,你需要切掉一些边,使这颗树分拆成若干个节点为偶数的联通分量,最多能切掉几条边.若不能切,输出-1. [分析]: 1.若点数n为奇数,因为奇数不可能分为偶数, ...

  3. Codeforces 982 C. Cut 'em all!(dfs)

    解题思路: 代码中有详细注解,以任意一点为根,dfs遍历这棵树. 每一个节点可能有好几个子树,计算每棵子树含有的节点数,再+1即为这整棵树的节点. 判断子树是否能切断与根之间的联系,如果子树含有偶数个 ...

  4. Hdu 5454,Minimum Cut,最近公共祖先+dfs遍历

    这道题补充了自己最近公共祖先的知识点: LCA(Lowest Common Ancestors)两种求法:①离线:tarjan+dfs:②在线算法,还没看 题意: 先给定一棵n个节点的树,然后给定一个 ...

  5. POJ2308连连看dfs+bfs+优化

    DFS+BFS+MAP+剪枝 题意:       就是给你一个10*10的连连看状态,然后问你最后能不能全部消没? 思路:      首先要明确这是一个搜索题目,还有就是关键的一点就是连连看这个游戏是 ...

  6. Codeforces 982 C. Cut 'em all! 图的遍历

    点击打开链接 C. Cut 'em all! time limit per test 1 second memory limit per test 256 megabytes input standa ...

  7. HDU Problem - 6214 Smallest Minimum Cut(最小割边,两种方法)

    题目链接 Problem Description Consider a network G=(V,E)G=(V,E)G=(V,E) with source sss and sink t" r ...

  8. Link Cut Tree 学习笔记

    Link Cut Tree 学习笔记 说在前边 最近补 CF 碰见一道 LCT ,就打算学习一下这个东西...顺便复习一下 splay. 具体算法及实现 参考了FlashHu, Candy? P369 ...

  9. 【HDU - 5452】Minimum Cut(树形dp 或 最近公共祖先lca+树上差分,转化tricks,思维)

    题干: Given a simple unweighted graph GG (an undirected graph containing no loops nor multiple edges) ...

最新文章

  1. 邬贺铨:解读5G技术关键点,及如何影响AIoT
  2. 【错误记录】Mac 中 IntelliJ IDEA 运行 Python 程序报错 ( End of statement expected )
  3. oracle中的NVL,NVL2,NULLIF,COALESCE函数使用
  4. springboot拦截器拦截提示_Springboot拦截器使用及其底层源码剖析
  5. 获取周/月的第一天最后一天
  6. CentOS挂载NTFS移动硬盘
  7. java 的转义字符,在正则表达式中应用
  8. 什么是创新?如何创新?
  9. TokenInsight:反映区块链行业整体表现的TI指数较昨日同期上涨0.41%
  10. Dijstra--讲解
  11. Unity性能优化之物理引擎的优化(一)
  12. protues 51单片机仿真电路图及代码
  13. windows清理_10款欧美流行的Windows清理软件
  14. 零基础数学建模学习日记Day1
  15. Windows10 永久激活查询/激活时间查询/激活查询命令/激活码查询
  16. 微信号注册又将有新规定了
  17. SCI声学期刊名以及影响因子
  18. java引用另一个程序图像,java – 在Android应用程序上显示图像的另一种方法
  19. 请按该计酬方式计算员工的工资。
  20. 最强蜗牛服务器维护祷告bug,最强蜗牛 这个游戏的玩家太难带了,竟然天天希望服务器有事...

热门文章

  1. 从芯片小厂成为显卡巨头,23年里,N厂经历了什么?
  2. 运用for 语句来计算 从1加到10的用法 C++
  3. adobe acrobat reader安装教程
  4. java-net-php-python-Java沈师周边美食资源管理系统计算机毕业设计程序
  5. 等价无穷小替换及其习题 笔记
  6. FZU 1076 穿越沙漠(逆推建模)(数学)
  7. MIGO 行项目屏幕自定义字段增强示例
  8. 如何在云服务器上部署web项目(CVM)
  9. echarts方形柱状图
  10. 清除PbootCms中的版权标识