递归,建立搜索树
另外有一个骚操作
printf("%5d",x);
d前边加数字可控制间距
#include
#include
#include
int const maxn=23,maxm=1148576,maxe=501000,inf=0x1f1f1f1f;
int n,use[maxn],vis[maxn];
inline void dfs(int pos)
{
if(pos==n+1)
{
for(int i=1;i<=n;i++)
printf("%5d",use[i]);
puts("");
return;
}
for(int i=1;i<=n;i++)
if(!vis[i])
use[pos]=i,vis[i]=true,dfs(pos+1),vis[i]=false;
}
int main()
{
scanf("%d",&n);
dfs(1);
return 0;
}
跟上一题唯一的区别是满足递增关系…
#include
#include
#include
int const maxn=23,maxm=1148576,maxe=501000,inf=0x1f1f1f1f;
int n,m;
int vis[maxn],use[maxn];
inline void dfs(int pos,int last)
{
if(pos==m+1)
{
for(int i=1;i
这题不会做,看了题解真想扇自己一巴掌,所以说做题还是自己想比较好
易发现,水瓶里的水只能是2的幂,所以2^n个初始的瓶子可以合为1个瓶子
我们发现这根本就是二进制加法…
于是我们把问题转化一下,把n用二进制表示,看看可以n的初始瓶子最少能表示为多少个2的幂的和
比如13=2^0 + 2^2 + 2^3,最少可以合并到3个瓶子
然后贪心的从低位加瓶子即可
正确性可以证明
#include
#include
#include
#define int long long
int const maxn=23,maxm=1148576,maxe=501000,inf=0x1f1f1f1f;
int n,k;
inline int lowbit(int x)
{
return x&-x;
}
int work(int x)
{
int num=0;
while(x)
{
num++;
x-=lowbit(x);
}
return num;
}
inline int get(int x)
{
int tot=0;
while(x)
{
tot+=x&1;
x>>=1;
}
return tot;
}
inline void solve()
{
int ans=0;
while(get(n)>k)
{
int pos=lowbit(n);
ans+=pos;
n+=pos;
}
printf("%lld",ans);
}
signed main()
{
scanf("%lld%lld",&n,&k);
solve();
return 0;
}
搜索水题,不过有坑点…
1.不要回溯时清掉访问标记,这又不是求最优解,有解的话是一定能搜到的
2.注意溢出的问题
3.注意只要洞跟下底面接触就能走 (而不是跟坐标原点求距离公式)
#include
#include
#include
#include
int const maxn=1101,maxm=1148576,maxe=501000,inf=0x1f1f1f1f;
int t,n,h,r;
int ans,vis[maxn];
int x[maxn],y[maxn],z[maxn],a[maxn];
inline int cmp(int x,int y)
{
return z[x]=h)
{
ans=true;
return;
}
vis[now]=true;
for(int j=1;j<=n;j++)
{
int i=a[j];
if(vis[i]||now==i)
continue;
long long dis=distant(x[now],y[now],z[now],x[i],y[i],z[i]);
if(dis<=(long long)4*pow(r))
dfs(i);
}
// vis[now]=false;
return;
}
int main()
{
scanf("%d",&t);
while(t--)
{
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(z,0,sizeof(z));
memset(vis,0,sizeof(vis));
scanf("%d%d%d",&n,&h,&r);
ans=0;
for(int i=1;i<=n;i++)
scanf("%d%d%d",&x[i],&y[i],&z[i]),a[i]=i;
std::sort(a+1,a+1+n,cmp);
for(int j=1;j<=n;j++)
{
int i=a[j];
if(z[i]<=r)
dfs(i);
}
if(ans)
puts("Yes");
else
puts("No");
}
return 0;
}
我真是太弱了…一开始还想建图…
建啥图啊,直接枚举每个点不就行了…
#include
#include
#include
int const maxn=1111,maxm=599500,maxe=501000,inf=0x1f1f1f1f;
int t,n,m,ans;
int map[maxn][maxn],ton[maxn],don[maxn];
inline bool check1(int u,int num)
{
if(!num)
return true;
for(int i=1;i<=num;i++)
if(!map[ton[i]][u])
return false;
return true;
}
inline bool check2(int u,int num)
{
if(!num)
return true;
for(int i=1;i<=num;i++)
if(map[don[i]][u])
return false;
return true;
}
inline void dfs(int pos,int numt,int numd)
{
if(pos==n+1)
{
if(numt&&numd)
ans++;
return;
}
if(check1(pos,numt))
ton[numt+1]=pos,dfs(pos+1,numt+1,numd),ton[numt+1]=0;
if(check2(pos,numd))
don[numd+1]=pos,dfs(pos+1,numt,numd+1),don[numd+1]=0;
}
int main()
{
scanf("%d",&t);
while(t--)
{
ans=0;
memset(map,0,sizeof(map));
scanf("%d%d",&n,&m);
for(int u,v,i=1;i<=m;i++)
scanf("%d%d",&u,&v),
map[u][v]=map[v][u]=true;
dfs(1,0,0);
printf("%d\n",ans);
}
}
经典的TSP问题!
一般解法
#include
#include
#include
#include
int const maxn=23,maxm=1148576,maxe=501000,inf=0x1f1f1f1f;
int n;double x[maxn],y[maxn];bool vis[maxn];
double ans=inf;
inline double pow(double x)
{
return x*x;
}
inline double distant(int last,int now)
{
return sqrt(pow(x[last]-x[now])+pow(y[last]-y[now]));
}
inline void dfs(int u,int pos,double len)
{
if(len>=ans)
return;
if(pos==n)
{
ans=std::min(ans,len);
return;
}
for(int i=1;i<=n;i++)
{
if(vis[i])
continue;
vis[i]=true;
dfs(i,pos+1,len+distant(u,i));
vis[i]=false;
}
return;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf",&x[i],&y[i]);
dfs(0,0,0);
printf("%.2lf",ans);
return 0;
}
状压dp
被无情卡常被迫吸了口氧…
f[i][j]表示i状态下走到j
#include
#include
#include
int const maxn=23,maxm=1148576,maxe=501000,inf=0x1f1f1f1f;
int n,map[maxn][maxn],mx;
int Pos[maxn];
int f[maxm][maxn];
inline void rin()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&map[i][j]);
return;
}
inline void pretreatment()
{
memset(f,0x1f,sizeof(f));
mx=(1<
难受啊!!!
打的表开到13没打大括号结果全完了,查了一上午…
另外我还真是navie…
一行一行搜就是了,非要向右向下同时搜…
该题关键在于优化搜索顺序
先填0少的行,优化搜索状态
#include
#include
#include
#include
int const maxn=13,maxm=1148576,maxe=501000,inf=0x1f1f1f1f;
int Zero[maxn],Map[maxn][maxn],lit[maxn][maxn],a[maxn],row[maxn][maxn],line[maxn][maxn];
int mx,ans=-1;
int cmp(int x,int y)
{
return Zero[x]
66分代码,无fuck说
剪枝如下
#include
#include
#include
#include
int const maxn=72,inf=0x3f3f3f3f;
double const esp=1e-5;
int n,L[maxn];
int sum,mx,mn,ans;
int len,vis[maxn],ton[maxn],cnt;
void dfs(register int num,register int lftV)
{
if(!num)
{
printf("%d",len);
exit(0);
}
if(!lftV)
{
register int next=-1;
for(register int i=cnt;i>=1;i--)
if(ton[L[i]])
{
next=i;
break;
}
if(next==-1&&num!=1)
return;
ton[L[next]]--,dfs(num-1,len-L[next]),ton[L[next]]++;
return;
}
for(register int i=cnt;i>=1;i--)
if(ton[L[i]]&&lftV>=L[i])
{
ton[L[i]]--,dfs(num,lftV-L[i]),ton[L[i]]++;
if(L[i]==lftV || len==lftV)
return;
}
return;
}
int main()
{
scanf("%d",&n);
for(register int a,i=1;i<=n;i++)
{
scanf("%d",&a);
if(a>50)
continue;
ton[a]++;
sum+=a,mx=std::max(mx,a),mn=std::min(mn,a);
}
for(register int i=mn;i<=mx;i++)
if(ton[i])
L[++cnt]=i;
for(len=mx;len<=sum/2;len++)
{
double num=(double)sum/len;
if(num!=(int)num)
continue;
dfs(num,len);
}
printf("%d",sum);
return 0;
}
这题显然是bfs,然而dfs直接爆搜可以过9个点…
DFS
#include
#include
#include
int const maxn=423,inf=0x1f1f1f1f;
int const dx[8]={2,1,2,1,-2,-1,-2,-1};
int const dy[8]={1,2,-1,-2,1,2,-1,-2};
int n,m,sx,sy,map[maxn][maxn],vis[maxn][maxn];
void dfs(int x,int y,int step)
{
map[x][y]=std::min(map[x][y],step);
for(int p=0;p<8;p++)
{
int vx=x+dx[p],vy=y+dy[p];
if(vx<1||vx>n||vy<1||vy>m)
continue;
if(map[vx][vy]>step+1)
dfs(vx,vy,step+1);
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&sx,&sy);
memset(map,0x1f,sizeof(map));
dfs(sx,sy,0);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
printf("%-5d",map[i][j]==inf?-1:map[i][j]);
puts("");
}
return 0;
}
BFS
#include
#include
#include
#include
int const maxn=432,inf=0x1f1f1f1f;
int const dx[8]={2,1,2,1,-2,-1,-2,-1};
int const dy[8]={1,2,-1,-2,1,2,-1,-2};
struct node
{
int x,y;
node(int x=0,int y=0):
x(x),y(y){}
};
int n,m,sx,sy,map[maxn][maxn];
inline void bfs()
{
std::queueq;
q.push(node(sx,sy));
map[sx][sy]=0;
while(!q.empty())
{
node u=q.front();
q.pop();
for(int p=0;p<8;p++)
{
node v=(node){u.x+dx[p],u.y+dy[p]};
if(v.x<1||v.x>n||v.y<1||v.y>m)
continue;
if(map[v.x][v.y]>map[u.x][u.y]+1)
q.push(v),map[v.x][v.y]=map[u.x][u.y]+1;
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&sx,&sy);
memset(map,0x1f,sizeof(map));
bfs();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
printf("%-5d",map[i][j]==inf?-1:map[i][j]);
puts("");
}
return 0;
}
不重复那就不下降呗…
#include
#include
int const maxn=111,inf=0x1f1f1f1f;
int ans,n,k;
void dfs(int pos,int now,int lftV)
{
if(pos==k&&!lftV) {ans++;return;}
if(pos==k||lftV<0) return;
for(int i=now;i<=lftV;i++)
dfs(pos+1,i,lftV-i);
}
int main()
{
scanf("%d%d",&n,&k);
dfs(0,1,n);
printf("%d",ans);
return 0;
}
可以不放那就从0开始呗…
#include
#include
int const maxn=111,inf=0x1f1f1f1f;
int ans,n,k;
void dfs(int pos,int now,int lftV)
{
if(pos==k&&!lftV) {ans++;return;}
if(pos==k||lftV<0) return;
for(int i=now;i<=lftV;i++)
dfs(pos+1,i,lftV-i);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ans=0;
scanf("%d%d",&n,&k);
dfs(0,0,n);
printf("%d\n",ans);
}
return 0;
}
恶心
爆搜即可
#include
#include
#include
DFS求四联通的模板题
#include
#include
#include
int const maxn=1111;
int const dx[4]={0,0,1,-1};
int const dy[4]={1,-1,0,0};
int n,m;
int fa[maxn*maxn],num[maxn*maxn],vis[maxn*maxn];
char Map[maxn][maxn];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int dfs(int x,int y)
{
if(fa[x*n+y])
return find(x*n+y);
fa[x*n+y]=x*n+y,num[x*n+y]=1;
for(int p=0;p<4;p++)
{
int vx=x+dx[p],vy=y+dy[p];
if(vx>=1&&vx<=n&&vy>=1&&vy<=n&&Map[x][y]!=Map[vx][vy])
{
dfs(vx,vy);
int fu=find(x*n+y),fv=find(vx*n+vy);
if(fu!=fv)
fa[fv]=fu,num[fu]+=num[fv];
}
}
return find(x*n+y);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",Map[i]+1);
for(int sx,sy,i=1;i<=m;i++)
{
scanf("%d%d",&sx,&sy);
printf("%d\n",num[dfs(sx,sy)]);
}
return 0;
}
杨辉三角形+枚举全排列
第一行的n个数分别为a,b,c,…,对于sum有一定的规律
如果n为4,那么sum是a+3b+3c+d。
如果n为5,那么sum是a+4b+6c+4d+e。
如果n为6,那么sum是a+5b+10c+10d+5e+f
不难发现,各项的系数就是杨辉三角
另外,求某一行的杨辉三角有窍门
再就是注意杨辉三角中第n行的第m个数表示的是 C n − 1 , m − 1 C_{n-1,m-1} Cn−1,m−1
#include
#include
#include
int const maxn=17;
int n,sum,vis[maxn],use[maxn],f[maxn];
void dfs(int pos,int tot)
{
if(pos==n+1)
{
if(tot!=sum)
return;
for(int i=1;i<=n;i++)
printf("%d ",use[i]);
exit(0);
}
if(tot>sum)
return;
for(int i=1;i<=n;i++)
if(!vis[i])
use[pos]=i,vis[i]=true,dfs(pos+1,tot+i*f[pos-1]),vis[i]=false,use[pos]=0;
return;
}
int main()
{
scanf("%d%d",&n,&sum);
f[0]=1,f[n-1]=1;
for(int i=1;i*2
后序遍历,尽展递归魅力
#include
#include
int const maxn=13;
int n;
char Map[maxn];
void find(int l,int r)
{
if(l!=r)
{
int mid=l+r>>1;
find(l,mid),find(mid+1,r);
}
int flag0=false,flag1=false;
for(int i=l;i<=r;i++)
{
if(Map[i]=='0')
flag0=true;
if(Map[i]=='1')
flag1=true;
}
if(flag0&&!flag1)
printf("B");
if(!flag0&&flag1)
printf("I");
if(flag0&&flag1)
printf("F");
return;
}
int main()
{
scanf("%d",&n);
scanf("%s",Map+1);
find(1,1<
另:substr(x,y)拷贝从x开始的长度为y的子串
#include
#include
#include
std::string sec,lst;
void before(std::string mid,std::string aft)
{
if(mid.size()>0)
{
char ch=aft[aft.size()-1];
std::cout<>sec>>lst;
before(sec,lst);
return 0;
}
裸的爆搜
#include
#include
#include
int const maxn=100110,maxm=201210;
struct E
{
int to,next;
E(int to=0,int next=0):
to(to),next(next){}
}e[maxm];
int head[maxn],cnt;
int n,m,ans;
int f[maxn],ind[maxn],oud[maxn];
inline void add(int u,int v)
{
e[++cnt]=(E){v,head[u]};
head[u]=cnt;
}
void dfs(int u)
{
if(!oud[u])
{
ans++;
return;
}
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
dfs(v);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int u,v,i=1;i<=m;i++)
scanf("%d%d",&u,&v),ind[v]++,oud[u]++,add(u,v);
for(int i=1;i<=n;i++)
if(!ind[i]&&oud[i])
dfs(i);
printf("%d",ans);
return 0;
}
花了1min记忆化一下,AC
#include
#include
#include
int const maxn=100110,maxm=201210;
struct E
{
int to,next;
E(int to=0,int next=0):
to(to),next(next){}
}e[maxm];
int head[maxn],cnt;
int n,m,ans;
int f[maxn],ind[maxn],oud[maxn];
inline void add(int u,int v)
{
e[++cnt]=(E){v,head[u]};
head[u]=cnt;
}
int dfs(int u)
{
if(f[u])
return f[u];
if(!oud[u])
return f[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
f[u]+=dfs(v);
}
return f[u];
}
int main()
{
scanf("%d%d",&n,&m);
for(int u,v,i=1;i<=m;i++)
scanf("%d%d",&u,&v),ind[v]++,oud[u]++,add(u,v);
for(int i=1;i<=n;i++)
if(!ind[i]&&oud[i])
ans+=dfs(i);
printf("%d",ans);
return 0;
}
挺好的题
易知一个丑数一定是由某比他小的丑数乘上s集合中的数得来的
这样我们可以分析出一个性质1
对于集合中的一个数x来说,假如他乘上丑数i得到丑数i+1,那么他只有乘上更大的丑数才能得到比i+1更大的丑数
这样我们就可以对于每个数i<=n,都枚举集合s中的元素
记录一下当前元素需要乘第几小的丑数才能比i-1大
这个寻找第一个大于i-1的数的过程可以用二分实现
然而我写跪了
对所有元素取min作为第i小的丑数
#include
#include
#include
#include
int const maxn=100110,maxm=111,inf=0x7f7f7f7f;
int n,k;
long long f[maxn];
int s[maxm],a[maxm];
/*
inline int find(int id,int check)
{
int ans=0,l=s[id],r=k;
while(l<=r)
{
int mid=l+r>>1;
if(a[id]*f[mid]>check)
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
return ans;
}
*/
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
// std::sort(a+1,a+1+n);
f[0]=1;
// for(int i=1;i<=k;i++)
// f[i]=9999;
for(int i=1;i<=k;i++)
{
long long minn=inf;
for(int j=1;j<=n;j++)
{
// s[j]=find(j,f[i-1]);
while(a[j]*f[s[j]]<=f[i-1])
s[j]++;
//根据性质1,我们只需要从上一次更新开始找即可
minn=std::min(minn,a[j]*f[s[j]]);
}
f[i]=minn;
}
printf("%lld",f[k]);
return 0;
}