题目描述
现有N件不可区分的物品,将它们分成10份,要求每份在1~3件之间,问有多少种方案,并按字典序输出所有方案。
输入格式
一个整数,表示N<=10000N<=10000。
输出格式
第一行一个数M,表示方案数。
接下来M行每行10个整数,表示1种方案。
样例数据
input
11
output
10
1 1 1 1 1 1 1 1 1 2
1 1 1 1 1 1 1 1 2 1
1 1 1 1 1 1 1 2 1 1
1 1 1 1 1 1 2 1 1 1
1 1 1 1 1 2 1 1 1 1
1 1 1 1 2 1 1 1 1 1
1 1 1 2 1 1 1 1 1 1
1 1 2 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 1
2 1 1 1 1 1 1 1 1 1
数据规模与约定
时间限制:1s1s
空间限制:256MB
显然标准的做法是dfs,但是由于devcpp和OJ抽风,我们这道题写了近半个小时也没调出来。所以这里用一种更简洁易懂好调的做法:
由于数字的个数是限定的,数字的大小范围也只有1到3,那就直接采用十重循环枚举十个数,然后判断即可。
#include
using namespace std;
int n,ans=0,t[10080][18]={};
int main()
{
freopen("allot.in","r",stdin);
freopen("allot.out","w",stdout);
cin>>n;
for(int a=1;a<=3;a++)
for(int b=1;b<=3;b++)
for(int c=1;c<=3;c++)
for(int d=1;d<=3;d++)
for(int e=1;e<=3;e++)
for(int f=1;f<=3;f++)
for(int g=1;g<=3;g++)
for(int h=1;h<=3;h++)
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
if(a+b+c+d+e+f+g+h+i+j==n)
{
ans++;
t[ans][1]=a;
t[ans][2]=b;
t[ans][3]=c;
t[ans][4]=d;
t[ans][5]=e;
t[ans][6]=f;
t[ans][7]=g;
t[ans][8]=h;
t[ans][9]=i;
t[ans][10]=j;
}
cout<<ans<<endl;
for(int i=1;i<=ans;i++)
{
for(int j=1;j<=10;j++)
{
if(j<10)printf("%d ",t[i][j]);
else printf("%d\n",t[i][j]);
}
}
return 0;
}
题目描述
流星雨是美丽的,但是流星落下来也能砸死人的。
有一大片流星要在海亮教育园的操场落下,而小x恰好在操场数星星。小x面临最大的问题不是浪漫,而是保住小命。
我们把海亮教育园的操场认为是坐标系的第一象限(以样例解释的图例为准)。小x现在位于坐标系的原点。
现在有M颗流星会落在海亮教育园的操场上,其中第i颗流星会在时刻T_i砸在坐标为(X_i, Y_i)的格子里。流星的力量会将它所在的格子,以及周围4个相邻的格子都化为焦土,当然小x也无法再在这些格子上行走,这样他会被烧伤。
小x从0时刻开始逃离,他只能上下左右移动,并且一个时刻只能移动一个格子,当然,这个格子必须是完好的。
现在小x想知道,最少经过多少时刻,他可以到达一个安全的格子。
输入格式
一个正整数M 接下来M行,每行3个整数Xi,Yi和Ti。分别表示第i颗流星落下的坐标和时间。保证所有坐标都在第一象限。
输出格式
一个整数,表示最少逃离时刻。如果逃离不了,那么输出-1,表示小x肯定被流星砸着了。
样例数据
input
4
0 0 2
2 1 2
1 1 2
0 3 5
output
5
【样例说明】
一共有4颗流星将坠落在操场,它们落地点的坐标分别是(0, 0),(2, 1), (1, 1)以及(0, 3),时刻分别为2,2,2,5。
在t=5时的牧场,离小x最近的安全的格子是(3,0)——不过由于早在第二颗流星落地时,小x直接跑去(3,0)的路线就被封死了。离小x第二近的安全格子为(4,0),但它的情况也跟(3,0)一样。再接下来的格子就是在(0,5)-(5,0)这条直线上。在这些格子中,(0,5),(1,4)以及(2,3)都能在5个单位时间内到达。
数据规模与约定
20% M<=25
40% M<=200
100% M<=50000 0 <= X_i <= 300;0 <= Y_i <= 300 0 <= T_i <= 1,000
时间限制:1s1s
空间限制:256MB
看到格点图,有移动操作的问题,并且移动代价都是1,基本上就可以判定是广搜问题了。
这道题的特殊之处在于流星不断落下,有时间的先后顺序,那么解决方案就是在二维数组上标记,如果是数字0就代表是安全点,如果不是一个大于0的的数字x则代表在第i秒及以后,这个格子不能行走,这就是流星的限制条件。根据这样的规则广搜,直到找到第一个数字为0的格子的时间就是答案。
#include
using namespace std;
int m,Map[1080][1080],dis[1080][1080],vis[1080][1080],safe;
int dx[5]={0,0,0,1,-1},dy[5]={0,1,-1,0,0};
struct node{int t,x,y;};
inline void input()
{
scanf("%d",&m);
memset(Map,127,sizeof(Map));
safe=Map[0][0];
for(int i=1;i<=m;i++)
{
int x,y,t;
scanf("%d%d%d",&x,&y,&t);
Map[x][y]=min(Map[x][y],t);
for(int j=1;j<=4;j++)
{
int tx=x+dx[j],ty=y+dy[j];
if(tx>=0&&ty>=0)Map[tx][ty]=min(Map[tx][ty],t);
}
}
}
inline bool Check(node p){return (Map[p.x][p.y]>p.t&&!vis[p.x][p.y]);}
inline int Search()
{
queue<node>Q;
Q.push(node{0,0,0});
dis[0][0]=0,vis[0][0]=true;
while(!Q.empty())
{
node temp=Q.front();Q.pop();
for(int i=1;i<=4;i++)
{
int tx=temp.x+dx[i],ty=temp.y+dy[i];
if(tx>=0&&ty>=0&&Check(node{dis[temp.x][temp.y]+1,tx,ty}))
{
vis[tx][ty]=true;
dis[tx][ty]=dis[temp.x][temp.y]+1;
if(Map[tx][ty]==safe)return dis[tx][ty];
Q.push(node{dis[tx][ty],tx,ty});
}
}
}
return -1;
}
int main()
{
freopen("meteor.in","r",stdin);
freopen("meteor.out","w",stdout);
input();
printf("%d\n",Search());
return 0;
}
题目描述
Farmer John在森林里迷路了,现在他急需要回家。
森林被分成了N*M的矩阵,每个单元格有一个字符来标示属性,’.'表示空地,‘V’表示Fj所在的位置,‘J’表示Fj家的位置。在森林里有很多危险的地方,危险的地方被标记为’+’。 Fj想要在回家的路上,让自己距离危险的地方尽可能的远,请你帮他设计一条线路,让这条线路上的每个点距离 危险的地方 最近的距离 最大。
假设Fj的位置为 (R,C),某个危险点的位置为 (A,B)Fj距离危险点的距离为:
|R-A| + |C-B|
当然,Fj必须要回家,也许他必须要经过危险的地方。
输入格式
第一行两个整数:N和M (1 ≤ N, M ≤ 500)
接下来N行,每行M个字符,范围是:’.’, ‘+’, ‘V’, ‘J’.
数据保证肯定有’V’, ‘J’,且至少有一个’+’
输出格式
一个整数,表示那个距离
样例数据
input
4 4
+…
…
…
V…J
output
3
input
4 5
…
.+++.
.+.+.
V+.J+
output
0
数据规模与约定
时间限制:1s1s
空间限制:256MB
这道题的解决分为两个步骤:
1.得到每一个安全的点离他最近的危险的距离
2.利用这些距离条件找到最优路径及最优解
对于第一个问题,其实是可以利用广搜解决的,就是有多个等价起始点的广搜问题。只需要将每一个危险的点提前加入队列,然后开始广搜即可。
对于第二个问题,我们可以通过dfs不断暴力查找路径,得到最优解。
#include
using namespace std;
struct pos{int x,y;}begin,end;
int n,m,Map[580][580]={},dval[580][580]={},Mindanger[580][580]={};
int vis[580][580];queue< pos >Q;
int dx[5]={0,0,0,1,-1},dy[5]={0,1,-1,0,0};
inline void input()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
char temp;cin>>temp;
if(temp=='.')Map[i][j]=1;
if(temp=='+')
{
Map[i][j]=0;
dval[i][j]=0;
vis[i][j]=true;
Q.push(pos{i,j});
}
if(temp=='V')
{
begin=pos{i,j};
Map[i][j]=1;
}
if(temp=='J')
{
end=pos{i,j};
Map[i][j]=1;
}
}
}
}
inline bool Check(int x,int y){return (x>=1&&y>=1&&x<=n&&y<=m);}
inline void Search_Dangerous_Value()
{
while(!Q.empty())
{
pos temp=Q.front();Q.pop();
for(int i=1;i<=4;i++)
{
int tx=temp.x+dx[i],ty=temp.y+dy[i];
if(Check(tx,ty)&&!vis[tx][ty])
{
vis[tx][ty]=true;
dval[tx][ty]=dval[temp.x][temp.y]+1;
Q.push(pos{tx,ty});
}
}
}
}
inline void Find_Path(int x,int y,int Min)
{
if(Min<=Mindanger[x][y])return;
Mindanger[x][y]=Min;
if(end.x==x&&end.y==y)return;
for(int i=1;i<=4;i++)
{
int tx=x+dx[i],ty=y+dy[i];
if(Check(tx,ty))Find_Path(tx,ty,min(dval[tx][ty],Min));
}
}
int main()
{
freopen("vuk.in","r",stdin);
freopen("vuk.out","w",stdout);
input();
Search_Dangerous_Value();
Find_Path(begin.x,begin.y,dval[begin.x][begin.y]);
printf("%d\n",Mindanger[end.x][end.y]);
return 0;
}
题目描述
李宗泽的爱好是在周末进行物理学实验,但事与愿违,实验将N个黑洞(2 <= N <= 12, N为even)具象化在了他的农场里,每个都有明确的坐标位置。
根据他的计算,李宗泽知道将会形成N/2对连接起来的黑洞。如果黑洞A和B被连成一对,那么任何物体进入黑洞A,将会以进入黑洞A的方向从黑洞B中出来;进入黑洞B,也会以进入时的方向从黑洞A中出来。举例来说,黑洞A在(0,0),黑洞B在(1,0),牛玉鑫从(1/2,0)开始向X轴正方向移动,进入黑洞B,从黑洞A中出来,将继续向X轴正方向移动,再次进入黑洞B,被困在一个循环里。
李宗泽知道每一个黑洞在他的农场上的具体坐标,牛玉鑫只会向X轴正方向移动,但却不知道牛玉鑫目前的位置。
请你帮助李宗泽计算共有多少种黑洞配对方法会使在不幸的位置的牛玉鑫陷入循环。
输入格式
第一行:一个正整数N;
第二到N+1行:每行两个整数X,Y描述一个黑洞的位置,每个坐标在0…1,000,000,000内。
输出格式
一个数,代表所有的会让牛玉鑫陷入循环的黑洞配对方法数。
样例数据
input
4
0 0
1 0
1 1
0 1
有4个黑洞,形成一个正方形的循环。
output
2
给这4个黑洞编号为1…4。如果将1和2相连,3和4相连,牛玉鑫从1和2之间或3和4之间出发时会陷入循环。相同的,如果连接1和3,2和4,牛玉鑫也会陷入循环。只有连接1和4,2和3,牛玉鑫从任何一个位置开始移动都不会陷入循环。
数据规模与约定
时间限制:1s1s
空间限制:256MB
这是一道搜索题,我们可以直接利用dfs暴力对n个黑洞直接进行配对连接,但本题的关键在于如何进行验证这是否是循环的。
我们从人物的移动入手,他只会沿x轴的正方向移动,所以可以预先处理出每一个黑洞右边离它最近的,纵坐标相同的黑洞,这必然是它走出这个黑洞后进入的下一个黑洞。
那么最暴力的验证思想就是枚举每一个黑洞作为进入的黑洞,利用我们预处理的数组O(1)的转移到下一个黑洞,不断转移,如果它转移了超过n次还能转移,那这n个黑洞就一点构成了环,因为黑洞总共只有n个。这就是完整的解决方案。
#include
using namespace std;
int n,x[200],y[200],Next[200],Partner[200],ans=0;
inline void input()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]);
}
inline void Find_Next()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(x[i]<x[j]&&y[i]==y[j])
{
if(!Next[i]||x[j]-x[i]<x[Next[i]]-x[i])
Next[i]=j;
}
}
}
}
inline bool Check()
{
for(int i=1;i<=n;i++)
{
int temp=i;
for(int j=1;j<=n;j++)
{
temp=Next[Partner[temp]];
}
if(temp)return true;
}
return false;
}
inline int dfs()
{
int flag=0,result=0;
for(int i=1;i<=n;i++)if(!Partner[i]){flag=i;break;}
if(!flag)
{
if(Check())return 1;
else return 0;
}
for(int i=flag+1;i<=n;i++)
{
if(!Partner[i])
{
Partner[i]=flag;
Partner[flag]=i;
result+=dfs();
Partner[i]=Partner[flag]=0;
}
}
return result;
}
int main()
{
freopen("aaaaa.in","r",stdin);
freopen("aaaaa.out","w",stdout);
input();
Find_Next();
printf("%d\n",dfs());
return 0;
}