搜索专题总结
第七章的例题做得差不多了,还有一道枚举二叉树和一道比较难的搜方块的没过,另外有一道火柴的用IDA*水过,并没有过大数据,由于这道可以用dancing links过,所以留着dancing links一坑。接下来总结下这章的收获,首先最重要的当然是不需要判重的高效率的IDA*以及估价函数的设计技巧;然后是bfs+hash写得更熟练了,如果hash需要erase那么就只能用指针版的,但是效率会很慢,否则就用数组版的。
做搜索题的几个要点:
1,估算最坏复杂度。
2,寻找合适的剪枝策略,估计剪枝的效果,根据情况选择IDA*还是bfs,最坏复杂度高但剪枝效果明显的优先IDA*。
3,想清楚代码的大致框架。
4,想清楚代码实现困难的细节以及可能出错需要注意的地方。
5,大胆快速的写吧。
下面是第七章的例题:
A题:
输出所有的xxxxx / xxxxx =N
只要枚举上面的数字就行了,复杂度<10^5,直接循环枚举。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
const double EPS=0.0000001;
const double Pi=acos(-1.0);
int n;
int a,b;
bool vis[maxn];
bool has[20];
bool check(int b)
{
MS0(has);
REP(i,1,5){
int x=b%10;b/=10;
if(vis[x]||has[x]) return 0;
has[x]=1;
}
return 1;
}
int main()
{
//freopen("in.txt","r",stdin);
int st=1;
while(cin>>n,n){
if(!st) puts("");
st=0;
MS0(vis);
a=0;
bool flag=0;
REP(i,0,9){
vis[i]=1;
a=a*10+i;
REP(j,0,9){
if(vis[j]) continue;
vis[j]=1;
a=a*10+j;
REP(k,0,9){
if(vis[k]) continue;
vis[k]=1;
a=a*10+k;
REP(l,0,9){
if(vis[l]) continue;
vis[l]=1;
a=a*10+l;
REP(x,0,9){
if(vis[x]) continue;
vis[x]=1;
a=a*10+x;
if(a%n==0&&check(a/n)){
flag=1;
printf("%05d / %05d = %d\n",a,a/n,n);
}
vis[x]=0;
a-=x;a/=10;
}
vis[l]=0;
a-=l;a/=10;
}
vis[k]=0;
a-=k;a/=10;
}
vis[j]=0;
a-=j;a/=10;
}
vis[i]=0;
a-=i;a/=10;
}
if(!flag) printf("There are no solutions for %d.\n",n);
}
return 0;
}
B题:
水题,暴力。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
const double EPS=0.0000001;
const double Pi=acos(-1.0);
int n;
ll a[maxn];
ll cal(int l,int r)
{
ll res=1;
REP(i,l,r) res*=a[i];
return res;
}
int main()
{
int casen=1;
while(cin>>n){
REP(i,1,n) scanf("%lld",&a[i]);
ll ans=0;
REP(l,1,n){
REP(r,l,n){
ll tmp=cal(l,r);
ans=max(ans,tmp);
}
}
printf("Case #%d: The maximum product is %lld.\n\n",casen++,ans);
}
return 0;
}
C题:
水题,先确定下范围再枚举。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
const double EPS=0.0000001;
const double Pi=acos(-1.0);
ll k,x,y;
struct St
{
ll x,y;
};
vector<St> ans;
int main()
{
while(cin>>k){
ans.clear();
for(y=k+1;;y++){
x=k*y/(y-k);
if(x<y) break;
if((k*y)%(y-k)==0){
x=k*y/(y-k);
if(x<y) break;
ans.push_back({x,y});
}
}
printf("%d\n",(int)ans.size());
for(int i=0;i<ans.size();i++){
printf("1/%lld = 1/%lld + 1/%lld\n",k,ans[i].x,ans[i].y);
}
}
return 0;
}
D题:
水题,dfs就行了。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
const double EPS=0.0000001;
const double Pi=acos(-1.0);
int n,a[maxn];
bool vis[maxn],isprime[maxn];
void getPrime()
{
memset(isprime,1,sizeof(isprime));
isprime[1]=0;
REP(i,2,maxn-1){
if(!isprime[i]) continue;
for(int j=i+i;j<maxn;j+=i) isprime[j]=0;
}
}
void dfs(int cur)
{
if(cur>n){
if(!isprime[a[n]+a[1]]) return;
REP(i,1,n) printf("%d%c",a[i],i==n?'\n':' ');
return;
}
REP(i,1,n){
if(!vis[i]&&isprime[a[cur-1]+i]){
a[cur]=i;
vis[i]=1;
dfs(cur+1);
vis[i]=0;
}
}
}
int main()
{
int casen=1;
getPrime();
int st=1;
while(cin>>n){
MS0(vis);
if(!st) puts("");
st=0;
printf("Case %d:\n",casen++);
a[1]=1;
vis[1]=1;
dfs(2);
}
return 0;
}
E题:困难的串。
很经典的题,只要不断往后添加然后判断就行了,关键在于判断的复杂度,由于substr(0,l-1)是已经判断过的,所以只要判断后缀就行了。

/// 19:43 2015/11/16
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
int n,L;
int cur;
bool flag;
string ans;
bool judge(string s)
{
int len=s.size();
for(int i=1;i<=len/2;i++){
//out<<s.substr(len-2*i,i)<<"_"<<s.substr(len-i,i)<<endl;
if(s.substr(len-2*i,i)==s.substr(len-i,i)) return false;
}
return true;
}
void dfs(string s)
{
if(flag) return;
if(cur==n){
ans=s;flag=1;return;
}
cur++;
REP(i,0,L-1){
string t=s+char('A'+i);
if(judge(t)) dfs(t);
}
}
int main()
{
//freopen("in.txt","r",stdin);
while(cin>>n>>L,(n||L)){
cur=0;flag=0;
dfs("");
REP(i,0,(int)ans.size()-1){
printf("%c",ans[i]);
if(i%64==63&&i!=(int)ans.size()-1) printf("\n");
else if(i%4==3&&i!=(int)ans.size()-1) printf(" ");
}
printf("\n%d\n",(int)ans.size());
}
return 0;
}
F题:
枚举排列就行了,复杂度能过,注意输入的处理。

/// 20:34~ 2015/11/16
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
char s[maxn];
vector<int> G[maxn];
int a[maxn],pos[maxn];
int b[maxn],ans;
int id[maxn],fid[maxn];
int n;
bool vis[maxn];
void build()
{
REP(i,1,8) G[i].clear();
memset(id,-1,sizeof(id));
n=0;
int len=strlen(s);
for(int i=0;i<len;){
int u=id[s[i]];
if(u==-1) u=id[s[i]]=++n,fid[n]=s[i];
int j;
for(j=i+2;j<len;j++){
if(s[j]==';') break;
int v=id[s[j]];
if(v==-1) v=id[s[j]]=++n,fid[n]=s[j];
G[u].push_back(v);
G[v].push_back(u);
}
i=j+1;
}
}
void update()
{
REP(i,1,n) pos[a[i]]=i;
int res=0;
REP(u,1,n){
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
res=max(res,abs(pos[u]-pos[v]));
}
}
if(res<ans){
REP(i,1,n) b[i]=a[i];
ans=res;
}
else if(res==ans){
bool flag=0;
REP(i,1,n){
if(fid[a[i]]<fid[b[i]]){
flag=1;break;
}
else if(fid[a[i]]>fid[b[i]]) break;
}
if(flag){
REP(i,1,n) b[i]=a[i];
}
}
}
void dfs(int cur,int now)
{
a[cur]=now;
vis[now]=1;
if(cur==n) update();
REP(i,1,n) if(!vis[i]) dfs(cur+1,i);
vis[now]=0;
}
void solve()
{
ans=INF;
REP(i,1,n) dfs(1,i);
REP(i,1,n) printf("%c ",fid[b[i]]);
printf("-> %d\n",ans);
}
int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%s",s)){
if(strcmp(s,"#")==0) break;
build();
solve();
}
return 0;
}
H题:
倒水。bfs都可以,注意由于求的是倒水量最小而不是次数最少,所以bfs要用优先队列,IDA*似乎不太适合,因为倒水量的范围比较大。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=8000100;
const int INF=(1<<29);
int s[3],d;
int ans,d_;
bool vis[maxn];
struct Node
{
int s[3];
int step;
friend bool operator<(Node A,Node B)
{
return A.step>B.step;
}
void debug()
{
printf("x=%2d y=%2d z=%2d step=%2d\n",s[0],s[1],s[2],step);
}
};
int st(Node u)
{
int res=0;
REP(i,0,2) res=res*201+u.s[i];
return res;
}
Node pop(Node u,int x,int y)
{
if(u.s[x]<=s[y]-u.s[y]){
u.step+=u.s[x];
u.s[y]+=u.s[x];
u.s[x]=0;
return u;
}
else{
u.step+=s[y]-u.s[y];
u.s[x]-=s[y]-u.s[y];
u.s[y]=s[y];
return u;
}
}
void bfs()
{
MS0(vis);
priority_queue<Node> q;
Node ss={0,0,s[2],0};
q.push(ss);
vis[st(ss)]=1;
ans=0;d_=0;
while(!q.empty()){
Node u=q.top();q.pop();
///u.debug();
REP(i,0,2){
if(u.s[i]>d_&&u.s[i]<=d){
d_=u.s[i];ans=u.step;
}
}
if(d_==d) break;
Node v;
/// 1->2
v=pop(u,0,1);
if(!vis[st(v)]) q.push(v),vis[st(v)]=1;
/// 1->3
v=pop(u,0,2);
if(!vis[st(v)]) q.push(v),vis[st(v)]=1;
/// 2->1
v=pop(u,1,0);
if(!vis[st(v)]) q.push(v),vis[st(v)]=1;
/// 2->3
v=pop(u,1,2);
if(!vis[st(v)]) q.push(v),vis[st(v)]=1;
/// 3->1
v=pop(u,2,0);//cout<<"01"<<" ";v.debug();
if(!vis[st(v)]) q.push(v),vis[st(v)]=1;
/// 3->2
v=pop(u,2,1);
if(!vis[st(v)]) q.push(v),vis[st(v)]=1;
}
}
int main()
{
//freopen("in.txt","r",stdin);
int T;cin>>T;
while(T--){
scanf("%d%d%d%d",&s[0],&s[1],&s[2],&d);
MS0(vis);
bfs();
printf("%d %d\n",ans,d_);
}
return 0;
}
I题:
很经典的状态空间搜索问题,由于不可走的区域很多,所以重新建图以减小复杂度,这里判重很容易,直接bfs,当然IDA*也可以。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
int w,h,m;
char ch[20][20];
vector<int> G[maxn];int n;
struct Node
{
char c;
int x;
friend bool operator<(Node A,Node B)
{
return A.c<B.c;
}
};
Node S[maxn],T[maxn];
int id[20][20];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
bool vis[300][300][300];
struct qNode
{
int x,y,z;
int d;
};
bool jud(int x,int y,int z,int nx,int ny,int nz)
{
if(m==1) return 1;
if(m==2){
if(nx==ny) return 0;
if(x==ny&&y==nx) return 0;
return 1;
}
if(m==3){
if(nx==ny||ny==nz||nz==nx) return 0;
if(x==ny&&y==nx) return 0;
if(y==nz&&z==ny) return 0;
if(z==nx&&x==nz) return 0;
return 1;
}
}
int bfs()
{
MS0(vis);
queue<qNode> q;
qNode s={S[1].x,S[2].x,S[3].x,0};
qNode t={T[1].x,T[2].x,T[3].x,0};
q.push(s);
vis[s.x][s.y][s.z]=1;
while(!q.empty()){
qNode u=q.front();q.pop();
int x=u.x,y=u.y,z=u.z,d=u.d;
if(x==t.x&&y==t.y&&z==t.z) return d;
for(int i=0;i<G[x].size();i++){
int nx=G[x][i];
for(int j=0;j<G[y].size();j++){
int ny=G[y][j];
for(int k=0;k<G[z].size();k++){
int nz=G[z][k];
if(!vis[nx][ny][nz]&&jud(x,y,z,nx,ny,nz)){
q.push({nx,ny,nz,d+1});
vis[nx][ny][nz]=1;
}
}
}
}
}
return -1;
}
int main()
{
//freopen("in.txt","r",stdin);
while(cin>>w>>h>>m){
if(w==0&&h==0&&m==0) break;
gets(ch[0]);
REP(i,1,h) gets(ch[i]+1);
n=0;
MS0(id);
int ks=0,kt=0;
MS0(S);MS0(T);
REP(i,1,h){
REP(j,1,w){
if(ch[i][j]!='#'){
id[i][j]=++n;
if(islower(ch[i][j])) S[++ks]={ch[i][j],n};
if(isupper(ch[i][j])) T[++kt]={ch[i][j],n};
}
}
}
REP(i,0,maxn-1) G[i].clear();
G[0].push_back(0);
REP(i,1,h){
REP(j,1,w){
int u=id[i][j];
if(!u) continue;
G[u].push_back(u);
REP(k,0,3){
int ni=i+dx[k],nj=j+dy[k];
int v=id[ni][nj];
if(!v) continue;
G[u].push_back(v);
}
}
}
sort(S+1,S+m+1);sort(T+1,T+m+1);
printf("%d\n",bfs());
}
return 0;
}
J题:剪纸问题。
又是一道很经典的状态空间搜索问题。这里以每个元素的相对位置来设计的估价函数剪枝效果明显,所以用IDA*,效率非常高。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define PB push_back
using namespace std;
typedef long long ll;
const int maxn=2000100;
const int INF=(1<<29);
int n;
struct Node
{
int a[11];
void read()
{
REP(i,1,n) scanf("%d",&a[i]);
}
};Node s;
bool judge(Node s)
{
REP(i,1,n){
if(s.a[i]!=i) return 0;
}
return 1;
}
Node cut(Node s,int l,int r,int L,int R)
{
Node res=s;
REP(i,0,R-L) res.a[l+i]=s.a[L+i];
int lt=l+R-L+1;
REP(i,0,r-l) res.a[lt+i]=s.a[l+i];
return res;
}
int Not(Node s)
{
int res=0;
REP(i,1,n-1) res+=(s.a[i]+1!=s.a[i+1]);
return res;
}
int dfs(Node s,int cur,int maxd)
{
if(cur==maxd){
if(judge(s)) return 1;
return 0;
}
if(cur*3+Not(s)>maxd*3) return 0;
int res=0;
REP(l,1,n-1){
REP(r,l,n-1){
REP(R,r+1,n){
Node ns=cut(s,l,r,r+1,R);
res|=dfs(ns,cur+1,maxd);
if(res) return 1;
}
}
}
return res;
}
int main()
{
//freopen("in.txt","r",stdin);
int casen=1;
while(cin>>n,n){
s.read();
int ans=INF;
REP(i,0,n){
if(dfs(s,0,i)){
ans=i;break;
}
}
printf("Case %d: %d\n",casen++,ans);
}
return 0;
}
K题:
又是一道经典的状态空间搜索问题。这里如果用bfs的话要分三次,而IDA*依旧优势明显,效率高,代码短,注意每一步只能改变一个,所以估价函数为cur+不一样的个数>maxd,这里不一样的个数取最大就可以了,就不用分三次了。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
struct State
{
int a[24];
};State s;
string str;
int ans,x;
int A[]={0,2,6,11,15,20,22};
int B[]={1,3,8,12,17,21,23};
int C[]={4,5,6,7,8,9,10};
int D[]={13,14,15,16,17,18,19};
int Y[]={6,7,8,11,12,15,16,17};
/*
0 1
2 3
4 5 6 7 8 9 10
11 12
3 4 5 6 7 8 19
20 21
22 23
*/
void debug(State s)
{
printf(" ");printf("%2d %2d\n",s.a[0],s.a[1]);
printf(" ");printf("%2d %2d\n",s.a[2],s.a[3]);
REP(i,4,10) printf("%2d ",s.a[i]);printf("\n");
printf(" ");printf("%2d %2d\n",s.a[11],s.a[12]);
REP(i,13,19) printf("%2d ",s.a[i]);printf("\n");
printf(" ");printf("%2d %2d\n",s.a[20],s.a[21]);
printf(" ");printf("%2d %2d\n",s.a[22],s.a[23]);
cout<<endl;
}
State mov(State s,int *A,bool tag)
{
if(tag){
int tmp=s.a[A[0]];
REP(i,1,6) s.a[A[i-1]]=s.a[A[i]];
s.a[A[6]]=tmp;
return s;
}
else{
int tmp=s.a[A[6]];
for(int i=6;i>=1;i--) s.a[A[i]]=s.a[A[i-1]];
s.a[A[0]]=tmp;
return s;
}
}
State go(State s,char ch)
{
State ns=s;
if(ch=='A') ns=mov(s,A,1);
if(ch=='B') ns=mov(s,B,1);
if(ch=='C') ns=mov(s,C,0);
if(ch=='D') ns=mov(s,D,0);
if(ch=='E') ns=mov(s,B,0);
if(ch=='F') ns=mov(s,A,0);
if(ch=='G') ns=mov(s,D,1);
if(ch=='H') ns=mov(s,C,1);
return ns;
}
int judge(State s)
{
REP(i,1,7) if(s.a[Y[i]]!=s.a[Y[0]]) return 0;
return s.a[Y[0]];
}
int Not(State s)
{
int cnt[4]={0};
REP(i,0,7){
cnt[s.a[Y[i]]]++;
}
return max(cnt[1],max(cnt[2],cnt[3]));
}
bool dfs(State s,int cur,int maxd,string road)
{
if(cur==maxd){
int xx=judge(s);
if(xx){
str=road;
x=xx;
//debug(s);
return 1;
}
return 0;
}
if(cur+8-Not(s)>maxd) return 0;
for(char ch='A';ch<='H';ch++){
State ns=go(s,ch);
if(dfs(ns,cur+1,maxd,road+ch)) return 1;
}
return 0;
}
int main()
{
//freopen("in.txt","r",stdin);
int st;
while(cin>>st){
if(st==0) return 0;
s.a[0]=st;
REP(i,1,23) scanf("%d",&s.a[i]);
//debug(s);debug(mov(s,C,0));
for(int i=0;;i++){
if(dfs(s,0,i,"")){
ans=i;break;
}
}
if(ans==0) puts("No moves needed");
else cout<<str<<endl;
printf("%d\n",x);
}
}
L题:
这应该是很经典的贪心。。。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
ll N,s1,v1,s2,v2;
ll solve1(ll N,ll s1,ll v1,ll s2,ll v2)
{
ll res=0;
REP(i,0,N/s1){
ll tmp=i*v1+((N-i*s1)/s2)*v2;
res=max(tmp,res);
}
return res;
}
ll solve2(ll N,ll s1,ll v1,ll s2,ll v2)
{
// a*s1=b*s2->v1>v2 v1/s1>v2/s2 -> v1*s2>v2*s1
if(v1*s2<v2*s1){
swap(s1,s2);swap(v1,v2);
}
ll d=__gcd(s1,s2);
ll a=s2/d,b=s1/d;
ll res=0;
REP(i,0,b-1){
ll tmp=i*v2+((N-i*s2)/s1)*v1;
res=max(res,tmp);
}
return res;
}
int main()
{
//freopen("in.txt","r",stdin);
int T;cin>>T;
int casen=1;
while(T--){
scanf("%lld%lld%lld%lld%lld",&N,&s1,&v1,&s2,&v2);
ll ans=0;
if(N/s1<maxn) ans=solve1(N,s1,v1,s2,v2);
else if(N/s2<maxn) ans=solve1(N,s2,v2,s1,v1);
else ans=solve2(N,s1,v1,s2,v2);
printf("Case #%d: %lld\n",casen++,ans);
}
return 0;
}
O题:
这题大数据没过却莫名其妙地AC了。。。用的是IDA*,看来如果拼人品的话就IDA*吧。。。由于这题的另一种解法是dancing links,有时间学dancing links的时候一定回来看这题。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);
int n,k;
struct State
{
bool has[61];
int cnt;
int c[61];
int sum_c,max_c;
int Cnt()
{
int res=0;
REP(d,1,n){
REP(r,0,n-d){
REP(c,1,n-d+1){
int x=1;
int st=r*(2*n+1)+c;
REP(j,0,d-1) x&=(has[st+j]&has[st+n+j*(2*n+1)]&has[st+n+d+j*(2*n+1)]&has[st+d*(2*n+1)+j]);
res+=x;
}
}
}
return res;
}
void cal_c()
{
MS0(c);max_c=0;sum_c=0;
REP(i,1,2*n*(n+1)){
if(has[i]){
has[i]=0;
int tmp=cnt;
cnt=Cnt();
c[i]=tmp-cnt;
max_c=max(c[i],max_c);
sum_c+=c[i];
has[i]=1;
cnt=tmp;
}
}
}
};State s;
bool dfs(State s,int cur,int maxd)
{
s.cal_c();
if(cur==maxd) return s.cnt==0;
if(cur+s.cnt-s.sum_c>maxd) return 0;
REP(i,1,2*n*(n+1)){
if(s.has[i]){
if(s.c[i]==s.max_c){
State ns=s;
ns.has[i]=0;
ns.cnt=s.cnt-s.c[i];
if(dfs(ns,cur+1,maxd)) return 1;
}
}
}
return 0;
}
int main()
{
//freopen("in.txt","r",stdin);
int T;cin>>T;
while(T--){
scanf("%d%d",&n,&k);
REP(i,1,2*n*(n+1)) s.has[i]=1;
REP(i,1,k){
int x;scanf("%d",&x);
s.has[x]=0;
}
s.cnt=s.Cnt();
s.cal_c();
int ans=INF;
REP(i,1,60){
if(dfs(s,0,i)){
ans=i;break;
}
}
printf("%d\n",ans);
}
return 0;
}
来源:https://www.cnblogs.com/--560/p/4987887.html
