$vjudge-$搜索专题题解

本秂侑毒 提交于 2020-02-07 06:47:35

退役了,刷点儿无脑水题$bushi$放松下$QwQ$

然后先放个链接,,,$QwQ$

$A$

虽然是英文但并不难$get$题目大意?就说给定一个数独要求解出来,$over$

昂显然直接$dfs$加剪枝就成?显然就是个考剪枝技巧的题呗$QwQ$

首先显然在$dfs$的过程中每次一定是找到可能的取值最少的那个格子填?

然后考虑怎么记录每个格子的取值数量?

昂可以考虑给每行每列每个九宫格分别开个二进制数存哪些数被用了,然后对每个格子就把它这行这列这九宫格或起来,剩下的就是能用的了$QwQ$.而且因为是个$dfs$所以可以设成全局变量$QwQ$

$over$

还有一个方法是$dlx$,老年退役选手不配拥有脑子不想学不写了$QwQ$

阿还有就我没想到很好的方法找可能的取值最少的格子,,,所以我决定先不写,,,发现能过于是就不写了$QwQQQQQ$

然后因为我是用$lowbit$找可能取值,所以找到的都是1嘛,所以在这题里面我都是1表示还没用0表示用了$QwQ$

#include<iomanip>
#include<cstdio>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define lowbit(x) (x&(-x))
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)

const int N=20;
int a[N][N],h[N],l[N],gz[N],tot=(1<<10)-2;
bool flg;
char str[N];
map<int,int>mapp;

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il int nam(ri i,ri j){return ((i-1)/3*3+(j-1)/3)+1;}
il void dfs(ri x,ri y)
{
    if(y>9)++x,y=1;
    if(flg || x>9)return void(flg=1);
    if(a[x][y]>1)return void(dfs(x,y+1));
    ri nw=h[x]&l[y]&gz[nam(x,y)];
    while(nw)
    {
        ri tmp=lowbit(nw);
        a[x][y]=tmp;h[x]-=tmp;l[y]-=tmp;gz[nam(x,y)]-=tmp;dfs(x,y+1);if(flg)return;
        h[x]+=tmp;l[y]+=tmp;gz[nam(x,y)]+=tmp;a[x][y]=0;nw-=tmp;
    }
}

int main()
{
    //freopen("A.in","r",stdin);freopen("A.out","w",stdout);
    ri T=read();rp(i,1,9)mapp[1<<i]=i;
    while(T--)
    {
        rp(i,0,15)h[i]=l[i]=gz[i]=tot;
        rp(i,1,9)
        {
            scanf("%s",str+1);
            rp(j,1,9)
            {
                a[i][j]=(1<<(str[j]^'0'))/2*2;//if(a[i][j]<2)a[i][j]=0;
                h[i]-=a[i][j],l[j]-=a[i][j],gz[nam(i,j)]-=a[i][j];//,printf("%d:(%d,%d)\n",nam(i,j),i,j);
            }
        }
        flg=0;dfs(1,1);
        rp(i,1,9){rp(j,1,9)printf("%d",mapp[a[i][j]]);printf("\n");}
    }
    return 0;
}
View Code

$B$

基本想法很$easy$咯,直接枚举长度然后$dfs$康康能不能拼出来,$over$

前面几题都在于剪枝?说说这题怎么剪枝嗷$QwQ$

首先显然长的先安排,不会证但感性理解十分显然昂$QwQ$

然后对于当前原始木棒,记录最近一次拼接的木棒长度,如果布星相同长度的就都可以弃了$QwQ$

第三个是如果存在某根木棒放入的第一根就布星就直接返回$false$,因为这些空木棒是等效的,如果这根木棍不能放入这根就一定都布星.

最后是如果某根木棒在放入一根木棍后拼凑成功了,但是之后搜索的时候发现后面的无法拼凑成功,就布星直接返回$false$.十分显然?就因为是从长到短放的,所以如果继续搜索下去就是用几根短木棍替代这根木棍,显然更劣$QwQ$

$over$

然后我依然打了个错误的$dfs$,,,就我开始想的是一根根木棍地安排,但感性理解下发现显然安排木棒的复杂度会低些,所以应该要从木棒入手,,,不然会$T$,,,不要问我怎么知道的$QAQ$

#include<algorithm>
#include<iomanip>
#include<cstdio>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define lowbit(x) (x&(-x))
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)

const int N=70;
int n,a[N],sum,len,cnt,stck[N],val;
bool gdgs=1,flg;

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il bool cmp(ri gd,ri gs){return gd>gs;}
void dfs(ri num)
{
    //printf("num=%d cnt=%d anum=%d\n",num,cnt,a[num]);
    if(flg)return;if(cnt>sum/len)return;if(num>n)return void(flg=1);
    rp(i,1,cnt)
    {
        if(stck[i]+a[num]<=len)
        {stck[i]+=a[num];dfs(num+1);stck[i]-=a[num];if(flg)return;if(stck[i]+a[num]==len)return;}
    }
    stck[++cnt]=a[num];dfs(num+1);--cnt;
}

int main()
{
    //freopen("B.in","r",stdin);freopen("B.out","w",stdout);
    while(gdgs)
    {
        n=read();val=0;sum=0;if(!n)return 0;rp(i,1,n)sum+=a[i]=read(),val=max(val,a[i]);sort(a+1,a+1+n,cmp);
        rp(i,val,sum)if(!(sum%i)){len=i;cnt=0;flg=0;dfs(1);if(flg)printf("%d\n",len),i=sum+10;}
        //len=40;cnt=0;flg=0;dfs(1);printf("flg=%d\n",flg);
    }
    return 0;
}
先放个会$T$的$code$
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define lowbit(x) (x&(-x))
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)

const int N=70;
int n,a[N],sum,len,val;
bool gdgs=1,flg,vis[N];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il bool cmp(ri gd,ri gs){return gd>gs;}
void dfs(ri stck_len,ri num,ri cnt)
{
    if(cnt>sum/len)return void(flg=1);
    if(stck_len==len)return void(dfs(0,1,cnt+1));
    ri pre=0;
    rp(i,num,n)
        if(!vis[i] && a[i]!=pre && stck_len+a[i]<=len)
        {
            vis[i]=1;dfs(stck_len+a[i],i+1,cnt);if(flg)return;
            pre=a[i];vis[i]=0;if(num==1)return;if(stck_len+a[i]==len)return;
        }
}

int main()
{
    //freopen("B.in","r",stdin);freopen("B.out","w",stdout);
    while(gdgs)
    {
        memset(vis,0,sizeof(vis));val=0;sum=0;flg=0;
        n=read();if(!n)return 0;rp(i,1,n)sum+=a[i]=read(),val=max(val,a[i]);sort(a+1,a+1+n,cmp);
        rp(i,val,sum/2)if(!(sum%i)){len=i;dfs(0,1,1);if(flg)printf("%d\n",len),i=sum+10;}
        if(!flg)printf("%d\n",sum);
    }
    return 0;
}
View Code

$C$

没看懂题先咕了$QwQ$

$D$

$16\times 16$看起来就很$dlx$,,,都要退役了我就不给自己找麻烦了懒得写了$QwQ$

$E$

开始想法是广搜,因为感觉长得就很$bfs$的样子?

但是这里广搜要注意下细节昂$QwQ$,就在$queue$里面不能只存一个数,,,$umm$说不清我直接把我反面教材先放上来趴$QwQ$.然后错在哪儿其实还挺显然不说了,没$get$的自己输下样例就发现问题了$QwQ$

#include<iomanip>
#include<cstdio>
#include<queue>
#include<cstring>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)

const int N=100+10;
bool gdgs=1;
int pre[N],que[N],cnt,n;

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il void bfs()
{
    queue<int>Q;Q.push(1);
    while(!Q.empty())
    {
        ri nw=Q.front();que[++cnt]=nw;Q.pop();
        rp(i,1,cnt){ri tmp=nw+que[i];if(tmp<=n)if(!pre[tmp]){pre[tmp]=nw,Q.push(tmp);if(tmp==n)return;}}
    }
}
void print(ri x){if(x==1)return void(printf("%d ",x));print(pre[x]);printf("%d ",x);if(x==n)printf("\n");}

int main()
{
    freopen("E.in","r",stdin);freopen("E.out","w",stdout);
    n=100;memset(pre,0,sizeof(pre));cnt=0;bfs();
    while(gdgs){n=read();if(!n)return 0;print(n);}
    return 0;
}
View Code

所以反正就发现如果广搜要记录所有路径,就不可做了

所以考虑用$idfs$,即迭代加深

迭代加深不难就不说了$QwQ$,直接放代码趴$QwQ$

#include<iomanip>
#include<cstdio>
#include<queue>
#include<cstring>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)

const int N=100+10;
bool gdgs=1,vis[N];
int a[N],n,dep;
bool flg;

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
void dfs(ri num)
{
    if(num>dep){if(a[dep]==n)flg=1;return;}
    memset(vis,0,sizeof(vis));
    my(i,num-1,1)
        my(j,num-1,1)
            if(a[i]+a[j]>a[num-1] && a[i]+a[j]<=n && !vis[a[i]+a[j]])
            {vis[a[i]+a[j]]=1,a[num]=a[i]+a[j];dfs(num+1);if(flg)return;}
}


int main()
{
    //freopen("E.in","r",stdin);freopen("E.out","w",stdout);
    while(gdgs)
    {
        n=read();if(!n)return 0;if(n==1){printf("1\n");continue;}flg=0;a[1]=1;dep=1;
        while(!flg){++dep;dfs(2);if(flg){rp(i,1,dep)printf("%d ",a[i]);printf("\n");}}
    }
    return 0;
}
View Code

$F$

感$jio$是道无脑$bfs$,,,但是码量似乎挺大的$QwQ$,,,,我我我我都要退役了就不给自己找麻烦了不做了$QwQQQQQ$

$G$

同上$QwQQQQQ$

$H$

题目大意说有$n$个城市之间有$m$条双向路,每条路要耗费一定的油量,每个城市的油价固定且已给出.有$q$个询问,表示从城市$s$走到$e$,油箱的容量为$c$,求最小花费

阿感觉有点儿像网络流24题的汽车加油问题,,,?设$f_{i,j}$表示到达位置$i$油量为$j$的最小花费,然后每次就两个决策?加油或者继续走.跑个$dij$就好,$over$

#include<cstring>
#include<iomanip>
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define e(i,x) for(ri i=head[x];i;i=edge[i].nxt)

const int N=1000+10,M=10000+10,Q=100+10,inf=1e9;
int n,m,q,p[N],head[N],ed_cnt,dis[N][Q];
bool vis[N][Q];
struct ed{int to,nxt,wei;}edge[M<<1];
struct ques{int x,y,z,id,as;}qs[Q];
struct node{int pos,dis,f;};

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il bool operator < (node gd,node gs){return gd.dis>gs.dis;}
il void ad(ri x,ri y,ri z){edge[++ed_cnt]=(ed){x,head[y],z};head[y]=ed_cnt;}
il bool cmp(ques gd,ques gs){return gd.x<gs.x;}
il void dij(ri S,ri T,ri f)
{
    memset(dis,63,sizeof(dis));memset(vis,0,sizeof(vis));priority_queue<node>Q;Q.push((node){S,0,0});dis[S][0]=0;
    while(!Q.empty())
    {
        node nw=Q.top();Q.pop();ri nwp=nw.pos,nwf=nw.f,nwdis=nw.dis;if(vis[nwp][nwf])continue;
        //printf("nw_pos=%d nw_f=%d nw_dis=%d\n",nwp,nwf,nwdis);
        vis[nwp][nwf]=1;if(nwp==T){printf("%d\n",nwdis);return;}
        //printf("   ? f=%d nwf=%d vis=%d dis=%d p=%d dis=%d\n",f,nwf,vis[nwp][nwf],dis[nwp][nwf],p[nwp],dis[nwp][nwf+1]);
        if(nwf+1<=f && !vis[nwp][nwf+1] && dis[nwp][nwf]+p[nwp]<dis[nwp][nwf+1])
            dis[nwp][nwf+1]=dis[nwp][nwf]+p[nwp],Q.push((node){nwp,dis[nwp][nwf+1],nwf+1});
        e(i,nwp)
        {
            if(nwf>=w(i))
                if(!vis[t(i)][nwf-w(i)] && dis[t(i)][nwf-w(i)]>nwdis)
                {
                    dis[t(i)][nwf-w(i)]=nwdis,Q.push((node){t(i),nwdis,nwf-w(i)});
                    //printf("t=%d dis=%d\n",t(i),nwdis);
                }
        }
    }
    printf("impossible\n");
}

int main()
{
    //freopen("H.in","r",stdin);freopen("H.out","w",stdout);
    n=read();m=read();rp(i,0,n-1)p[i]=read();rp(i,1,m){ri x=read(),y=read(),z=read();ad(x,y,z);ad(y,x,z);}q=read();
    while(q--){ri x=read(),y=read(),z=read();dij(y,z,x);}
    return 0;
}
View Code

$I$

题目大意就说给个图求$K$短路$QwQ$?

关于$K$短路,因为要退役了也懒得写学习笔记了$QwQ$,就只大概港下$QwQ$

常见方法就跑个$spfa+A*$(其实是个假算法,,,,$QwQ$不过操过这道题还是欧克的了$w$),然后$A*$的评估函数就$f(x)=dis_x+g_x$,$dis$就当前点到起点的距离,$g_x$就当前点到终点的距离.

然后答案的话,当一个节点第$K$次出队时,答案是它的优先级;当终点第$K$次出队时,答案是它的路程

$over$?

#include<cstring>
#include<iomanip>
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define tt(i) edget[i].to
#define wt(i) edget[i].wei
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define e(i,x) for(ri i=head[x];i;i=edge[i].nxt)
#define et(i,x) for(ri i=headt[x];i;i=edget[i].nxt)

const int N=1000+10,M=100000+10;
int n,m,S,T,K,head[N],ed_cnt,dis[N],vis[N],edt_cnt,headt[N];
struct ed{int to,nxt,wei;}edge[M<<1],edget[M<<1];
struct node{int f,g,pos;};

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il bool operator < (node gd,node gs){return gd.f>gs.f;}
il void ad(ri x,ri y,ri z){edge[++ed_cnt]=(ed){x,head[y],z};head[y]=ed_cnt;}
il void adt(ri x,ri y,ri z){edget[++edt_cnt]=(ed){x,headt[y],z};headt[y]=edt_cnt;}
il void spfa(ri T)
{
    queue<int>Q;memset(dis,63,sizeof(dis));dis[T]=0;vis[T]=1;Q.push(T);
    while(!Q.empty())
    {
        ri nw=Q.front();Q.pop();vis[nw]=0;
        et(i,nw)if(dis[tt(i)]>dis[nw]+wt(i)){dis[tt(i)]=dis[nw]+wt(i);if(!vis[tt(i)])vis[tt(i)]=1,Q.push(tt(i));}
    }
}
il int solv(ri S,ri T)
{
    priority_queue<node>Q;if(dis[S]==dis[0])return -1;memset(vis,0,sizeof(vis));Q.push((node){dis[S],0,S});
    while(!Q.empty())
    {
        node nw=Q.top();Q.pop();ri nwf=nw.f,nwg=nw.g,nwp=nw.pos;++vis[nwp];
        if(vis[T]==K)return nwf;if(vis[nwp]>K)continue;
        e(i,nwp)if(vis[t(i)]<K)Q.push((node){dis[t(i)]+nwg+w(i),nwg+w(i),t(i)});
    }
    return -1;
}

int main()
{
    freopen("I.in","r",stdin);freopen("I.out","w",stdout);
    n=read();m=read();rp(i,1,m){ri x=read(),y=read(),z=read();ad(y,x,z);adt(x,y,z);}S=read();T=read();K=read();
    spfa(T);if(S==T)++K;printf("%d\n",solv(S,T));
    return 0;
}
View Code

$J$

题目大意就是要解八数码问题,然后要求输出步骤$QwQ$

$bfs$就成?$QwQ$

如果不成我再来$upd$,,,?

$K$

$L$

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!