2017 Xian ACM Summer Training Warm-up Exercise 1

来源:互联网 发布:阿里云服务器安全设置 编辑:程序博客网 时间:2024/05/22 06:33

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();    }}
原创粉丝点击