题面
Description
Input
Output
Sample Input
输入1:
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
输入2:
1 17
12 3
4 3
2 3
5 4
10 2
3 3
12 2
0 1
1 3
10 1
6 2
12 1
11 3
5 2
12 4
2 2
7 2
Sample Output
输出1:
3
输出2:
6
Data Constraint
思路
作为Day1的第三题还是有点难的,废话,不难怎么能做第三题呢?
不皮了,这题我的做法是
D
F
S
DFS
DFS,据说某些dalao用
B
F
S
+
h
a
s
h
BFS+hash
BFS+hash过了这道题。其实我的做法有点小问题,后面还会说到。
DFS的做法:
每次进入递归程序先把能做的三带,四带做完,把剩下的对子、单张、三张和炸弹打出去,步数与
a
n
s
ans
ans取
m
i
n
min
min值。接着把单顺,双顺,三顺都模拟一遍,答案就出来了。
Code
#include<cstdio>//by hzq
#include<cstring>
#define clean(x) memset(x,0,sizeof(x))
#define inf 99999999
using namespace std;
int t,n,ans,x,y;
int sum,jl[30];
int c[30];
int min(int mn1,int mn2){if(mn1>mn2) return mn2;return mn1;}
void dg(int step)
{
if(step>=ans) return ;
sum=0,clean(jl);
for(int i=0;i<=13;++i) jl[c[i]]++;
while(jl[4]>0&&jl[2]>1) jl[4]--,jl[2]-=2,sum++;
while(jl[4]>0&&jl[1]>1) jl[4]--,jl[1]-=2,sum++;
while(jl[4]>0&&jl[2]>0) jl[4]--,jl[2]--,sum++;
while(jl[3]>0&&jl[2]>0) jl[3]--,jl[2]--,sum++;
while(jl[3]>0&&jl[1]>0) jl[3]--,jl[1]--,sum++;
ans=min(ans,step+sum+jl[1]+jl[2]+jl[3]+jl[4]);
for(int i=2;i<=13;++i)
{
int cnt=i;
while(c[cnt]>=3) cnt++;
if(cnt-i>=2)
{
for(int j=i+1;j<=cnt-1;++j)
{
for(int p=i;p<=j;++p) c[p]-=3;
dg(step+1);
for(int p=i;p<=j;++p) c[p]+=3;
}
}
}
for(int i=2;i<=11;++i)
{
int cnt=i;
while(c[cnt]>=2) cnt++;
if(cnt-i>=3)
{
for(int j=i+2;j<=cnt-1;++j)
{
for(int p=i;p<=j;++p) c[p]-=2;
dg(step+1);
for(int p=i;p<=j;++p) c[p]+=2;
}
}
}
for(int i=2;i<=10;++i)
{
int cnt=i;
while(c[cnt]>=1) cnt++;
if(cnt-i>=5)
{
for(int j=i+4;j<=cnt-1;++j)
{
for(int p=i;p<=j;++p) c[p]--;
dg(step+1);
for(int p=i;p<=j;++p) c[p]++;
}
}
}
}
int main()
{
freopen("landlords.in","r",stdin);
freopen("landlords.out","w",stdout);
scanf("%d%d",&t,&n);
for(int i=1;i<=t;++i)
{
ans=inf,clean(c);
for(int j=1;j<=n;++j)
{
scanf("%d%d",&x,&y);
if(x==1) x=13;
else if(x) x--;
c[x]++;
}
dg(0),printf("%d\n",ans);
}
return 0;
}
这里还有另外一种 D F S DFS DFS的方法
#include<bits/stdc++.h>//by zhy
#define rg register
#define Fu(i,a,b) for(rg int i=(a);i<=(b);i++)
#define Fd(i,a,b) for(rg int i=(a);i>=(b);i--)
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline int read(){ int f=1,x=0; char s=getchar(); while(s<'0'||s>'9') { if (s=='-') f=-1; s=getchar(); } while(s>='0'&&s<='9') { x=x*10+s-'0'; s=getchar(); } return x*f; }
using namespace std;
int t,n,N,a,v[20],b,ans,j,y;
void dfs(int o,int num){
if(n==0){
ans=min(ans,o);
return ;
}
if(ans<=o) return ;
int s1=0,s2=0,s3=0,bj=0,sum=0;
Fu(i,1,13) sum+=(v[i]+1)/2;
if(sum<=num){
if(ans>o) ans=o,y=num-sum;
return ;
}
Fu(i,1,13){
if(v[i]>=1) s1++;
else s1=0;
if(v[i]>=2) s2++;
else s2=0;
if(v[i]>=3) s3++;
else s3=0;
if(i!=13){
if(s1>=5){
Fd(j,i,i-s1+1) v[j]--;
n-=s1;
dfs(o+1,num);
Fd(j,i,i-s1+1) v[j]++;
n+=s1;
bj=1;
}
if(s2>=3){
Fd(j,i,i-s2+1) v[j]-=2;
n-=s2*2;
dfs(o+1,num);
Fd(j,i,i-s2+1) v[j]+=2;
n+=s2*2;
bj=1;
}
if(s3>=2){
Fd(j,i,i-s3+1) v[j]-=3;
n-=s3*3;
dfs(o+1,num);
Fd(j,i,i-s3+1) v[j]+=3;
n+=s3*3;
bj=1;
}
}
if(v[i]>=3){
v[i]-=3,n-=3;
dfs(o+1,num+1);
v[i]+=3,n+=3;
bj=1;
}
if(v[i]==4){
v[i]-=4,n-=4;
dfs(o+1,num+2);
v[i]+=4,n+=4;
bj=1;
}
}
if(bj==0){
ans=min(ans,o+sum-num);
return ;
}
}
int main(){
fre(landlords);
t=read(),N=read();
while(t--){
n=N;
memset(v,0,sizeof(v));
ans=N,j=0,y=0;
Fu(i,1,n){
a=read(),b=read();
if(a==0)j++;
else{
if(a>2)a-=2;
else{
a+=11;
}
v[a]++;
}
}
n-=j;
dfs(0,0);
if(j>0&&y==0)ans++;
printf("%d\n",ans);
}
return 0;
}
还有比赛的时候一次就AC的 B F S + h a s h BFS+hash BFS+hash
#include<iostream>//by pmx
#include<cstdio>
using namespace std;
int hash[1000001][2];
int T,n;
int k[500001][15];
int prime[21]={13,131,373,499,641,773,929,1051,1181,1297,1439,1553,1667,1801};
int head,tail,bz;
int check(int x)
{
int w=x%999991;
while(hash[w][0]==T&&(hash[w][1]!=0&&hash[w][1]!=x))
{
w++;
if(w>1000000)
w=0;
}
if(hash[w][0]==T&&hash[w][1]==x) return 1;
hash[w][0]=T;
hash[w][1]=x;
return 0;
}
void add()
{
tail++;
int hash_num=0,bbz=0;
k[tail][14]=k[head][14]+1;
for(int i=0;i<=13;i++)
{
k[tail][i]=k[head][i];
if(k[tail][i]>0)
bbz=1;
hash_num+=k[head][i]*prime[i];
}
if(bbz==0)
{
bz=1;
printf("%d\n",k[tail][14]);
}
if(check(hash_num)==1)
tail--;
return ;
}
void a_kind(int x,int num)
{
if(k[head][x]<num) return ;
k[head][x]-=num;
add();if(bz==1) return ;
k[head][x]+=num;
return ;
}
void two_kind(int x,int num1,int num2)
{
if(k[head][x]<num1) return ;
k[head][x]-=num1;
for(int i=0;i<=13;i++)
if(i!=x&&k[head][i]>=num2)
{
k[head][i]-=num2;
add();if(bz==1) return ;
k[head][i]+=num2;
}
k[head][x]+=num1;
return ;
}
void three_kind(int x,int num1,int num2,int num3)
{
if(k[head][x]<num1) return ;
k[head][x]-=num1;
for(int i=0;i<=13;i++)
if(i!=x&&k[head][i]>=num2)
{
k[head][i]-=num2;
for(int j=0;j<=13;j++)
if(j!=x&&j!=i&&k[head][j]>=num3)
{
k[head][j]-=num3;
add();if(bz==1) return ;
k[head][j]+=num3;
}
k[head][i]+=num2;
}
k[head][x]+=num1;
return ;
}
void lian(int x,int num,int len)
{
if(x==0||x==2) return ;
int qi=x,i=0;
while(x!=2)
{
if(k[head][x]>=num)
{
++i;
k[head][x]-=num;
if(i>=len)
{
add();if(bz==1) return ;
}
x++;
if(x>13) x=1;
}
else break;
}
while(qi!=x)
{
k[head][qi]+=num;
qi++;
if(qi>13) qi=1;
}
}
int main()
{
freopen("landlords.in","r",stdin);
freopen("landlords.out","w",stdout);
scanf("%d%d",&T,&n);
while(T>0)
{
head=1,tail=1;
for(int i=0;i<=14;i++)
k[head][i]=0;
for(int i=1;i<=n;i++)
{
int x,b;
scanf("%d%d",&x,&b);
k[head][x]++;
}
bz=0;
while(head<=tail)
{
for(int i=0;i<=13;i++)
if(k[head][i]>0)
{
a_kind(i,1);if(bz==1) break;
a_kind(i,2);if(bz==1) break;
a_kind(i,3);if(bz==1) break;
a_kind(i,4);if(bz==1) break;
two_kind(i,3,1);if(bz==1) break;
two_kind(i,3,2);if(bz==1) break;
two_kind(i,4,2);if(bz==1) break;
three_kind(i,4,1,1);if(bz==1) break;
three_kind(i,4,2,2);if(bz==1) break;
lian(i,1,5);if(bz==1) break;
lian(i,2,3);if(bz==1) break;
lian(i,3,2);if(bz==1) break;
}
if(bz==1)
break;
head++;
}
T--;
}
fclose(stdin);fclose(stdout);
return 0;
}
小彩蛋
还好这题是随机数据,不然一堆人都会被hack掉,试一下下面这个数据吧:
输入:
1 8
3 1
3 2
3 3
3 4
4 1
4 2
4 3
4 4
输出:
1
解释:
四个三带两对四。
我给出的第二个代码是不会被hack掉的。