第一题
交换【推荐】 (Standard IO)
Description
给定1到N的一个排列,再给定一些允许的交换方法,要求用最少的交换次数把该排列变为1,2,3,,,N。
Input
第一行包含两个整数N(1<=N<=12)和M(1<=M<=N*(N-1)/2),表示序列的长度以及允许的交换方案。
第二行输入1到N个初始排列情况。
接下来M行,每行两个整数A和B描述一个允许的交换方案,表示允许把当前排列中的第A个数和第B个数进行交换,保证A和B不相同。
输入保证一定存在解。
Output
输出一个整数表示最少需要的交换次数。
Sample Input
输入1:
2 1
2 1
1 2
输入2:
3 2
2 1 3
1 3
2 3
输入3:
5 5
1 2 3 4 5
1 5
2 5
1 4
1 1
3 5
Sample Output
输出1:
1
输出2:
3
输出3:
0
题解:一开始用单向dfs,10分。
开始的起始状态我们是知道的,最终转移到的状态我们也是知道的,而且每种操作的改变对于正着做和反着做都是相同的,所以应该是双向bfs加上哈希表判重。
不过,我们如何记录它的状态?
开应该12维的布尔数组是不太科学的,因为N很小只用12,而且1213=106993205379072 这个数是可以用long long存的下的。那么我们就将每一个序列看成应该12进制的数,再将它转换成为应该10进制数。这样,我们就可以将每一个序列变成一个数。
ps:今天这题是我第一次用哈希表,然后我用数组模拟了队列
代码:
#include<iostream>
#include <cstdio>
#include <cstring>
#define LL long long
#define MOD 1000007
using namespace std;
long long ha[MOD],da1[3*MOD],date[3*MOD],z[15],s;
int g[MOD],n,m,l,now,a[15],t[15],cz[150][2],f[15];
bool bz[MOD];
int hash(LL x)
{
int k=x%MOD;
while(ha[k]&&ha[k]!=x)
{
k=(k+1)%MOD;
}
return k;
}
long long zz()
{
LL sum=0;
for(int i=1;i<=n;i++)
{
sum+=t[i]*z[n-i];
}
return sum;
}
void aa(LL x)
{
for(int i=1;i<=n;i++)
{
f[i]=x/z[n-i];
x=x%z[n-i];
}
}
int main()
{
z[0]=1;
for(int i=1;i<=13;i++)
z[i]=z[i-1]*12;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];t[i]=i-1;
a[i]--;
}
for(int i=1;i<=m;i++)
{
cin>>cz[i][0]>>cz[i][1];
}
da1[1]=zz();
l=hash(da1[1]);
ha[l]=da1[1];
bz[l]=1;
memcpy(t,a,sizeof(t));
date[1]=zz();
l=hash(date[1]);
ha[l]=date[1];
if(da1[1]==date[1])
{
printf("0\n");//相同直接输出0嘛
return 0;
}
int i=0,j=1,p=0,q=1;
while((i<j)&&(p<q))
{
i++;
aa(date[i]);
now=g[hash(date[i])];
for(int k=1;k<=m;k++)
{
memcpy(t,f,sizeof(t));
l=t[cz[k][0]];
t[cz[k][0]]=t[cz[k][1]];
t[cz[k][1]]=l;
s=zz();
l=hash(s);
if(ha[l]==s)
{
if(bz[l])
{
cout<<g[l]+now+1;
return 0;
}
}
else
{
j++;
date[j]=s;
ha[l]=s;
bz[l]=0;
g[l]=now+1;
}
}
p++;
aa(da1[p]);
now=g[hash(da1[p])];
for(int k=1;k<=m;k++)
{
memcpy(t,f,sizeof(t));
l=t[cz[k][0]];
t[cz[k][0]]=t[cz[k][1]];
t[cz[k][1]]=l;
s=zz();
l=hash(s);
if(ha[l]==s)
{
if(!bz[l])
{
cout<<g[l]+now+1;
return 0;
}
}
else
{
q++;
da1[q]=s;
ha[l]=s;
bz[l]=1;
g[l]=now+1;
}
}
}
return 0;
}
第二题
送披萨 (Standard IO)
Time Limits: 3000 ms Memory Limits: 256000 KB Detailed Limits
Goto ProblemSet
Description
Alice刚刚收到一份送披萨的工作,每天工作前,他会收到一份送披萨的清单,必须按照上面的顺序依次送。
城区被分为R*C块区域,行编号为1到R,列编号1到C,对于每个单元格,可以向左或向右移到相邻的单元格中,只有在第一列和第C列时才允许向上和向下移动。
披萨店在坐上角(1,1)处,这里也是Alice出发的地方,Alice把每天需要送的披萨都带上,这样他就没有回到店里去取。
进入每个单元格都需要花费一定的时间。
编程计算Alice送完所有披萨最少需要花费多少时间。
Input
第一行包含两个整数R和C(1<=R<=2000,1<=C<=200)。
接下来R行,每行C个整数,表示进入每个单于格需要花费的时间,每个数都在0到5000之间。
下一行输入一个整数D(1<=D<=200000),表示某天需要送的披萨数量。
接下来D行,每行包含两个整数A和B(1<=A<=R,1<=B<=C),表示送披萨的位置,必须按照输入顺序依次去送,D个地址没有相同的。
Output
输出最少需要花费的时间。
Sample Input
输入1:
3 3
1 8 2
2 3 2
1 0 1
3
1 3
3 3
2 2
输入2:
2 5
0 0 0 0 0
1 4 2 3 2
4
1 5
2 2
2 5
2 1
Sample Output
输出1:
17
输出2:
9
Data Constraint
Hint
【样例解释】
样例1中,可以选择以下路线:(1, 1), (2, 1), (3, 1), (3, 2), (3, 3), (2, 3), (1, 3), (2, 3), (3, 3), (2, 3),(2, 2),粗体的部分为送披萨的位置,总时间为1+2+1+0+1+2+2+2+1+2+3=17
【数据范围】
70%的数据满足R<=250
第三题
买玩具 (Standard IO)
Time Limits: 3000 ms Memory Limits: 262144 KB Detailed Limits Special Judge
Goto ProblemSet
Description
N个小朋友都很喜欢玩具,一开始每个人都没有玩具,但他们可以去买,买玩具有规定:必须两个小朋友一起去买,而且必须买2个玩具,两人各出一半钱,但玩具归谁就不一定了,要用石头剪刀布决定,赢者得2个,平各得1个,输者得0个。
经过若干次购买,每个人手里都有若干个玩具,但由于小朋友记性不好,只能回忆起M次购买是哪两个个小朋友去的,其他都不记得了。
请你帮忙输出一种可能的购买情况。
Input
第一行包含两个整数N和M(1<=N<=100,0<=M<=1000),表示小朋友数量,以及能够回忆起来的购买数量,小朋友编号1到N。
第二行包含N个整数,表示每个小朋友手中玩具的数量。
接下来M行,每行包含两个整数,表示回忆起来的参与这次购买的小朋友的编号。
。
Output
输出一共购买的次数X。
接下来X行,每行描述一次购买的情况,由三个整数a,b,c组成,a,b表示参与这次购买的小朋友,c只能取0,1或2,表示a在这次购买中得到的玩具数量。
注意:保证购买次数最多只有1000次,并且保证有解,但不是唯一的,输出任意一个即可。
Sample Input
输入1:
2 3
5 1
1 2
1 2
1 2
输入2:
4 3
5 3 1 1
1 3
2 3
4 1
输入3:
5 0
3 0 2 4 1
Sample Output
输出1:
3
1 2 1
1 2 2
1 2 2
输出2:
5
1 3 1
2 3 2
4 1 0
2 4 1
1 3 2
输出3:
5
1 2 2
1 3 1
4 2 2
3 4 0
3 5 1
Data Constraint
Hint
【样例解释】
样例1中,有2个小朋友,编号1和2,最终1号小朋友有5个玩具,2号有1个。
第1次购买,2人各得1个玩具,第2、3次,都是1号小朋友得2个玩具,2号没有得到玩具。
题解:dalao说用网络流,本蒟蒻不会。