Gym 101246(ACM ICPC 2010-2011, NEERC, Southern Subregional Contest Russia, Saratov)

PROBLEM B D E F ARE INCLUDED

Problem B. 3D City Model

题意:

        用积木搭成 N * M 的物体,并给出每块的高度求表面积。

思路:

        对于每一块区域,有基础面积 4 * H + 2

        再分别减去与上下左右的重合面积(两个区域的最小高度)

代码:

#include <bits/stdc++.h>

using namespace std;
int a[105][105];
char x;
int dirx[4]={1,0,-1,0};
int diry[4]={0,1,0,-1};
int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int n,m;
    while(cin>>n>>m){
        long long ans=0;
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>x;
                x-='0';
                a[i][j]=x;
            }
        }
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(a[i][j]) ans+=4*a[i][j]+2;
            for(int k=0;k<4;k++){
                ans-=min(a[i+dirx[k]][j+diry[k]],a[i][j]);
            }
        }
        cout<<ans<<endl;
    }
}

Problem D. Fire in the Country

题意:

   有n个点,m条无向边(m >= n-1),棋子在点1,一人走一步,只能走到直接关联的点,然后点1着火了,每次从1开始扩散,与着火点直接关联的点都会着火,而且不会灭,谁往火力走谁输。第一个人甲先走,问谁输。

思路:

   由于给出的大部分是图,要先 bfs 染色确定火在第几步会烧到那个点,同时记录下到达哪个点时该谁走。

   再从 1 点开始 dfs 搜索。在搜索中我们考虑一下几种情况:

   1.当前点是一个终点,那么如果这个点轮到甲走,他已无路可走则甲输,反之则乙输。

   2.当前点是一个分叉点,走到这一点可以选择一条路径继续走。那么:

     (1)如果是轮到甲走,如果分叉点下存在一条甲的必胜路径,则甲胜。若一条甲的必胜路径都没有,则甲输。

     (2)如果是轮到乙走,如果分叉点下存在一条甲的必输路径,则乙胜。若所有的路径都是甲的必胜路径,则甲胜。

代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1000+100;
int n,m,color[MAXN],son[MAXN];
bool peo[MAXN];
vector <int> mp[MAXN];
void ini(){
    for(int i=1;i<=n;i++){
        color[i]=MAXN;
        mp[i].clear();
        son[i]=0;
        peo[i]=0;
    }
}
void make_color(){
    queue <int> que;
    que.push(1);
    color[1]=0;
    peo[1]=0;
    int pos,now;
    while(!que.empty()){
        pos=que.front();
        que.pop();
        int len=mp[pos].size();
        for(int i=0;i<len;i++){
            now=mp[pos][i];
            if(color[now]>color[pos]){
                son[pos]++;
                peo[now]=!peo[pos];
                if(color[now]==MAXN) que.push(now);
                color[now]=color[pos]+1;
            }
        }
    }
}
int solve(int pos){
    if(son[pos]==0) return peo[pos];
    int len=mp[pos].size();
    int ans=0;
    for(int i=0;i<len;i++)
        if(color[mp[pos][i]]>color[pos])
            ans+=solve(mp[pos][i]);
    if(!peo[pos]){
        if(ans) return 1;
        else return 0;
    }else{
        if(ans==son[pos]) return 1;
        else return 0;
    }
}
int main(){
    ios::sync_with_stdio(false);
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    while(cin>>n>>m){
        int x,y;
        ini();
        for(int i=0;i<m;i++){
            cin>>x>>y;
            mp[x].push_back(y);
            mp[y].push_back(x);
        }
        make_color();
        if(solve(1)) cout<<"Vladimir"<<endl;
        else cout<<"Nikolay"<<endl;
    }
}




Problem E. Kidnapping

转自:http://blog.csdn.net/tianyuhang123/article/details/62054038

题意:

抓劫匪的题,最后总结为有n条路,a[x][y]表示第x条路与第y条路之间的距离,由于绑匪将人绑着,所以人只能计算出走的路程给出计算的路程问最后到达的劫匪窝点可能是那条街(每次都是从第一条路开始)

思路:

直接搜索就行了,输入一个数把可能的点标记,然后再输入后来的数,但每次标记时需要把以前标记过得请0,最后被标记的那些点就是可能的点

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int a[205][205],b[205],c[205],n,m,h;
    while(cin>>n)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            cin>>a[i][j];
        }
        cin>>m;
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        b[1]=1;
        for(int i=1;i<=m;i++)
        {
          cin>>h;
          for(int j=1;j<=n;j++)
          {
              if(b[j])
              {
                  for(int k=1;k<=n;k++)
                  {
                      if(a[j][k]==h)
                      c[k]=1;
                  }
              }
          }
          for(int j=1;j<=n;j++)
          b[j]=c[j];
          memset(c,0,sizeof(c));
        }
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            if(b[i]==1)
            {
                c[sum++]=i;
            }
        }
        cout<<sum<<endl;
        if(sum>0)
        {
            for(int i=0;i<sum-1;i++)
            printf("%d ",c[i]);
            printf("%d\n",c[sum-1]);
        }
    }
    return 0;
}




Problem F. Elevator

题意:
坐电梯然后在一个楼层有好多人按了不同的楼层,根据先来后到的顺序,不过如果在前面人和原楼层之间的人可以在过程中下楼梯
思路:
从头往后遍历一遍如果后面有在前面人俺的楼层之间的直接输出然后把标记清0,不过需要注意有两种情况,有可能是从高楼层到低楼层(降序输出),从低楼层到高楼层(升序输出)
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;


int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int m,n;
    int a[105],b[105],h,flag;
    while(cin>>n>>m)
    {
        memset(b,0,sizeof(b));
        for(int i=1;i<=n;i++)
        {cin>>a[i];
         b[a[i]]=1;
        }
        int h=0;
        for(int i=1;i<=n;i++)
        {
            if(b[a[i]])
            {
              int g;
              if(a[i]>m)
              g=1;
              else
              g=-1;
              for(int k=m;k!=a[i];k+=g)
              {
                  if(b[k]==1)
                  {
                    if(h==n-1)
                    cout<<k<<endl;
                    else
                    cout<<k<<" ";
                    h++;
                    b[k]=0;
                  }
              }
              if(h==n-1)
              cout<<a[i]<<endl;
              else
              cout<<a[i]<<" ";
              h++;
              b[a[i]]=0;
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值