您的位置:首页 > 大数据 > 人工智能

2017 Xian ACM Summer Training Warm-up Exercise 1

2017-07-10 09:21 176 查看

A题Chocolate

http://poj.org/problem?id=1322

题意:

c种巧克力,每种数量无穷大,取出n个放桌上,如果出现同种巧克力的就必须两个一起吃掉,即桌面上同种巧克力只能有0个或者1个。问取出n个后剩余m种巧克力的概率。

tip:

方程比较好想,就是dp[i][j]表示一共取了I次,桌子上还有j个的概率,那么

dp[i][j] = dp[i-1][j-1](拿到的是桌子上之前没有的颜色)(c-j+1)/c+dp[i-1][j+1](j+1)/c;

i,j范围都是1e5,那么数组都开不下,1)每个只与i-1项有关,所以可以滚动,且我们知道桌面上同种巧克力不可能出现多余1个,那么就是说j的范围就是100,但是外层循环i 还是会超时,考虑到每层递推都是一样的,可以用构造矩阵,矩阵快速幂即可。

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int c,n,M;
const int maxn = 110;

struct Matrix{
double m[maxn][maxn];
}a;
void print(Matrix a){
for(int i = 0 ; i <= 5 ; i++){
for(int j = 0 ; j <= 5 ; j++)
printf("%.3f ",a.m[i][j]);
printf("\n");
}
cout <<"\n";
}
void get_mar(){
for(int i =  0 ; i <= c ; i++){
for(int j = 0 ; j <= c; j++){
if(i == 0 && j == 1)    a.m[i][j] = 1.0;
else if(i == c && j == c-1) a.m[i][j] = 1.0;
else if(j == i+1 )    a.m[i][j] = (double)(c-j+1)/c;
else if(j == i-1)   a.m[i][j] =(double) (j+1)/c;
else a.m[i][j] = 0.0;
}
}
//print(a);
}

Matrix Mul_mar(Matrix a,Matrix b){
Matrix p;
for(int i = 0 ;i <= c ; i++)
for(int j = 0 ; j <= c; j++)
p.m[i][j] = 0.0;
for(int i =  0 ;i <= c ;i++){
for(int k = 0 ; k <= c ; k++)
if(a.m[i][k])
for(int j = 0 ; j <= c ; j++)
if(b.m[k][j])
p.m[i][j] = (p.m[i][j]+a.m[i][k]*b.m[k][j]);
}
return p;
}

Matrix quick_mar(int n){
Matrix tmp;
for(int i = 0 ;i <= c ; i++)
for(int j = 0 ; j <= c; j++)
tmp.m[i][j] = 0;
for(int i = 0 ; i <= c ; i++)  tmp.m[i][i] = 1;
while(n){
if(n & 1)   tmp = Mul_mar(tmp,a);
n >>= 1;
a = Mul_mar(a,a);
}
// print(tmp);
return tmp;
}

int main(){
while(~scanf("%d",&c)&&c){
scanf("%d%d",&n,&M);
if(M > c){
printf("0.000\n");
continue;
}
get_mar();
Matrix p = quick_mar(n);
printf("%.3f\n",p.m[0][M]);
}
}


B题Game Prediction :

http://poj.org/problem?id=1323

题意:

有M个人,一人N张牌,每轮牌面最大的人赢(牌面只可能是1~M*N中的一个数且不重复),给出一个人的牌,求其至少能够赢的局数。

##tip:

贪心,最开始觉得题意说的不明确,以为是博弈。。。后来并不知道别人怎么出牌,就只能从大到小,没有比自己大的一定赢了,有的话,手头最大的不一定赢,一直到没有才行

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
int m, n,ca;
const int maxn = 1100;
int cards[maxn];
void sov(){
memset(cards, 0, sizeof(cards));
for(int i = 0; i < n; i++){
int t;
scanf("%d", &t);
cards[t] = 1;
}
int lar = 0, ans=0;
for(int i = m*n; i > 0; i--){
if(!cards[i]) lar++;
else{
if(lar == 0) ans++;
else lar--;
}
}
printf("Case %d: %d\n", ++ca,ans);
}
int main(){
while(~scanf("%d%d",&m,&n) && m && n){
sov();
}
}


C题Holedox Moving :

http://poj.org/problem?id=1324

题意:

在n*m的地图上,给出长度为L的蛇身体各个节位置,以及有k个点是墙,问蛇从初始位置走到(1,1)点的最小步数。蛇不能撞墙,不能撞自己的身体。

tip:

看上去像是bfs,遇到问题:状态判重方法和已经每次图形中不可达点都在变。

神奇的hash,对整个图hash是肯定不行得了,考虑对身体hash,固定头的位置,已经身体上每个点对于上一块身体是在上下左右(2进制表达)哪个位置,2进制后,可以用位运算快速的知道移动后身体位置(我们知道后一块是前一快上次在的位置)。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
int n,m,l,ca;
struct node{
int hx,hy;
int body[8];
int step;
};
int len;
queue<node> qq;
int dirx[]={0,0,1,-1};
int diry[]={1,-1,0,0};
int mp[22][22];
bool state[22][22][1<<14];
int trans(int x,int y){
if (x == -1 && y == 0 )
return 1;  //shang
if (x == 1&&y == 0)
return 2; //下
if (x == 0 && y == -1)
return 3 ;      //左
if (x == 0 &&y == 1)
return 4;   //右
}
node get_new(node t,int x,int y){
node res;
for (int i = len;i > 1;i--){
res.body[i] = t.body[i-1];
}
int dir = trans(t.hx-x,t.hy-y);
res.body[1] = dir;
res.step = t.step + 1;
res.hx = x;
res.hy = y;
return res;

}
void get_xy(int &tx,int &ty,int dir,int x,int y){
if (dir == 1)//上
tx = x-1,ty = y;
if (dir == 2)//xia
tx = x+1,ty = y;
if (dir == 3)//zuo
tx = x,ty = y-1;
if (dir == 4)//you
tx = x,ty = y+1;
}
void deal_map(node t){//body
int lastx,lasty;
for (int i = 1;i <= len;i++){
int tx,ty;
if (i == 1){
get_xy(tx,ty,t.body[i],t.hx,t.hy);
}
else{
get_xy(tx,ty,t.body[i],lastx,lasty);
}
lastx = tx;
lasty = ty;
if (mp[tx][ty] == 0)
mp[tx][ty] = 2;
}
}
void un_deal_map(node t){
int lastx,lasty;
for (int i = 1;i <= len;i++){
int tx,ty;
if (i == 1){
get_xy(tx,ty,t.body[i],t.hx,t.hy);
}
else{
get_xy(tx,ty,t.body[i],lastx,lasty);
}
lastx = tx;
lasty = ty;
if (mp[tx][ty] == 2)
mp[tx][ty] = 0;
}
}
int get_body_num(node y){
int ret = 0;
for (int i = 1;i <= len;i++){
ret += (y.body[i]-1)* ( 1<<(2*(i-1)) );
}
return ret;
}
void bfs(){
int ans = -1;
while(!qq.empty()){
node t=qq.front();
qq.pop();
if (t.hx == 1 && t.hy == 1 ){
ans = t.step;
break;
}
deal_map(t);        //设蛇身为障碍
for (int i = 0;i < 4;i++){
int x = t.hx+dirx[i];
int y = t.hy+diry[i];
if (mp[x][y]) continue;         //如果不可行
node res = get_new(t,x,y);      //移动后得到的新状态res
int ret=get_body_num(res);      //计算是否出现过当前状态
if (state[res.hx][res.hy][ret] == true)
continue;
state[res.hx][res.hy][ret]=true;
qq.push(res);
}
un_deal_map(t);     //恢复地图
}

printf("Case %d: %d\n",++ca,ans);
}
void init(){
node tm;
memset(mp,0,sizeof(mp));
memset(state,0,sizeof(state));
for (int i = 0;i <= m+1;i++)
mp[0][i] = 1;
for (int i = 0;i <= m+1;i++)
mp[n+1][i] = 1;
for (int i = 0 ;i <= n+1;i++)
mp[i][0]=1;
for (int i = 0;i <= n+1;i++)
mp[i][m+1] = 1;
int xx,yy;
int lastx,lasty;
int delx,dely;
scanf("%d%d",&tm.hx,&tm.hy);
for (int i = 1;i <= l-1;i++){
scanf("%d%d",&xx,&yy);
if (i == 1) {
delx = xx - tm.hx;
dely = yy - tm.hy;
}
else{
delx = xx - lastx;
dely = yy - lasty;
}
tm.body[i] = trans(delx,dely);
lastx = xx;
lasty = yy;
}
len = l-1;
int num;

scanf("%d",&num);
for (int i = 1;i <= num;i++) {
scanf("%d%d",&xx,&yy);
mp[xx][yy] = 1;
}
tm.step = 0;
while(!qq.empty())  qq.pop();
int ret = get_body_num(tm);
state[tm.hx][tm.hy][ret]=true;
qq.push(tm);
}
int main(){
while(~scanf("%d%d%d",&n,&m,&l)){
if(n == 0 && m == 0 && l == 0)  break;
init();
bfs();
}
}


D题Machine Schedule :

http://poj.org/problem?id=1325

题意:

有两个机器A和B,A机器有n个模式,B机器有m个模式,两个机器最初在0模式(wa点)

然后有k个作业,每个作业有三个参数i,a,b

i代表作业编号,a和b代表第i作业要么在A机器的a模式下完成【或者】在B机器的b模式下完成

问两个机器总共最少变换多少次可以完成所有作业

tip:

最小点覆盖,等于最大匹配,跑个匈牙利就好啦

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 10100;
int n,m,k,tot,head[maxn];
struct node{
int to,next;
}edges[maxn];

void add(int u,int v){
edges[tot].to = v;edges[tot].next = head[u];head[u] = tot++;
}
void init(){
memset(head,-1,sizeof(head));
tot = 0;
for(int i = 1; i <= k ; i++){
int l,r,jo;
scanf("%d%d%d",&jo,&l,&r);
if(l == 0 || r == 0)    continue;
add(l,r+m);
}
}
bool use[maxn];
int linker[maxn];

bool dfs(int u){
int v;
for(int k = head[u]; k != -1; k = edges[k].next){
int to = edges[k].to;
if(!use[to]){
use[to] = true;
if(linker[to] == -1 || dfs(linker[to])){
linker[to] = u;
return true;
}
}
}
return false;
}
void sov(){
int res = 0;
memset(linker,-1,sizeof(linker));
for(int i = 1 ; i <= m ; i++){
memset(use,0,sizeof(use));
if(dfs(i)){
res++;
}
}
printf("%d\n",res);
}

int main(){
while(~scanf("%d",&m)&&m){
scanf("%d%d",&n,&k);
init();
sov();
}

}


E - Mileage Bank

http://poj.org/problem?id=1326

题意:

给出航线 的长度,经济舱500公里以下算500公里,否则算actual mileage。商务舱算实际里程×1.5。头等舱实际里程×2。根据给出的航班,求出总的mileage bank中的值。

tip:

注意一下字符串结束的方式就好了

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 11000;
char f[maxn],t[maxn],ty[2];
int dis,t2,t1,t3,flag;
void sov(){
int ans = 0;
while(1){
scanf("%s",f);
if(f[0] == '#'){
flag = 1;
return;
}
if(f[0] == '0') break;
scanf("%s%d%s",t,&dis,ty);
if(dis < 500){
t1 = 500;
}
else   t1 = dis;
t2 = dis+ (dis%2 == 0? dis/2:(dis+1)/2) ;
t3 = dis+dis;
// cout <<ty[0]<<"  t1 = "<<t1<<" "<<t2<<" "<<t3<<endl;
if(ty[0] == 'Y') ans+=t1;
else if(ty[0] == 'B')   ans+=t2;
else ans+=t3;
// cout <<"asn =  "<<ans<<endl;
}
printf("%d\n",ans);
//if(flag == 1)   return;
}
int main(){
while(1){
sov();
if(flag == 1)   break;
}
}


G题G - Radar Installation:

http://poj.org/problem?id=1328

题意:

假设海岸线是一条无限延伸的直线。陆地在海岸线的一侧,而海洋在另一侧。每一个小的岛屿是海洋上的一个点。雷达坐落于海岸线上,只能覆盖d距离,所以如果小岛能够被覆盖到的话,它们之间的距离最多为d。

题目要求计算出能够覆盖给出的所有岛屿的最少雷达数目。

tip:

每个点到能被x轴管辖的范围就是

t[i].first = x-sqrt(r*r-y*y);

t[i].second = x+sqrt(r*r-y*y);

就变成了最少选多少个点能使得所有区间内都有至少一个点,左端点排序,贪心

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int n;
const int maxn = 1100;
typedef pair<double,double>pii;
pii t[maxn];
int ca = 0,flag;
double r,x,y;
void init(){
flag = 0;
for(int i = 0 ; i < n ; i++){
scanf("%lf%lf",&x,&y);
if(y > r)   flag = 1;
t[i].first = x-sqrt(r*r-y*y);
t[i].second = x+sqrt(r*r-y*y);
}
sort(t,t+n);

}
void sov(){
int ans = 1;
double r = t[0].second,l = t[0].first;
for(int i = 1 ; i < n ; i++){
if(t[i].second < r ){
r = t[i].second;l= t[i].first;
}
else if(t[i].first <= r){
l = t[i].first;
}
else{
l = t[i].first;r = t[i].second;
ans++;
}
}
printf("Case %d: %d\n",++ca,ans);
}
int main(){
while(~scanf("%d%lf",&n,&r)){
if(n == 0 && r == 0)    break;
if(n == 0){
printf("Case %d: 0\n",++ca);
continue;
}
init();
if(flag == 1){
printf("Case %d: -1\n",++ca);
continue;
}
sov();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: