狗狗40题~ (Volume C)

A - Triangles

记忆化搜索嘛。搜索以某三角形为顶的最大面积,注意边界情况。

#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
           
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define INF 200000000
           
typedef long long ll;
int dp[110][220];
char g[110][220];           
int main(){
   int n,h,cs=1;
   while(scanf("%d",&n) && n){
      for(int i=0;i<n;i++)scanf("%s",g[i]);
      memset(dp,0,sizeof dp);
      
      printf("Triangle #%d\n",cs++);
      if(n==1){
          printf("The largest triangle area is %d.\n\n",g[0][0]=='#'?0:1);
          continue;
      }
      
      h=0;
      for(int j=0;j<2*n-1;j++)if(g[0][j]!='#')dp[0][j]=h=1;
      for(int i=1;i<n;i++){
         int j;
         for(j=0;j<2*(n-i);j+=2)if(g[i][j]!='#'){
            int f=i-1,p=j+1;
            while(f>=0&&g[f][p]!='#'&&g[f][p+1]!='#')f--,p+=2;
            dp[i][j]=min(1+dp[i-1][j],i-f);
            h=max(h,dp[i][j]);
         }
      }
      if(g[n-2][1]!='#'){dp[n-2][1]=1;h=max(h,1);}
      for(int i=n-3;i>=0;i--){
          int j;
          for(j=1;j<2*(n-i)-1;j+=2)if(g[i][j]!='#'){
             if(j<2)dp[i][j]=1;
             else{
             int f=i+1,p=j-1;
             while(f<n && j<2*(n-f)-1 && g[f][p]!='#' && g[f][p+1]!='#')f++;
             dp[i][j]=min(1+dp[i+1][j-2],f-i);
             }
             h=max(h,dp[i][j]);
          }
      }
      printf("The largest triangle area is %d.\n\n",h*h);
   }
   return 0;
}

B - Domino Effect

基本就是最短路问题,权值为正,最后要用 t=(dis[i]+dis[j]+g[i][j])/2.0 计算边上最后一个多米诺倒下的时间。

#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
           
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define INF 20000000000LL
           
typedef long long ll;
int g[505][505],n,m,vis[505];
ll d[505];
double t;int x,y;
void dijkstra(){
   for(int i=2;i<=n;i++)d[i]=INF;
   d[1]=0;
   for(int i=0;i<n;i++){
      int u;
      ll tm=INF;
      for(int j=1;j<=n;j++)if(!vis[j]&&d[j]<tm){
         u=j;tm=d[j];
      }
      if(tm>=INF)break;
      vis[u]=1;
      for(int j=1;j<=n;j++)if(g[u][j]!=-1&&!vis[j])
          d[j]=min(d[j],g[u][j]+d[u]);
   }
   for(int i=1;i<=n;i++){
      if(t<d[i]){x=i;y=0;t=d[i];}
      for(int j=1;j<i;j++)if(g[i][j]!=-1){
         double temp=(g[i][j]+d[i]+d[j])/2.0;
         if(t<temp){x=j;y=i;t=temp;}
      }
         
   }
}           
int main(){
    int a,b,l,cs=1;
    while(scanf("%d%d",&n,&m) && n){
       memset(g,-1,sizeof g);
       memset(vis,0,sizeof vis);
       t=0;x=1;y=0;
       for(int i=0;i<m;i++){
           scanf("%d%d%d",&a,&b,&l);
           g[a][b]=g[b][a]=l;
       }
       dijkstra();
       printf("System #%d\n",cs++);
       if(!y){
         printf("The last domino falls after %.1lf seconds, at key domino %d.\n\n",t,x);
       }else{
         printf("The last domino falls after %.1lf seconds, between key dominoes %d and %d.\n\n",t,x,y);
       }
   }
   return 0;
}


D - The New Villa

这种题应该一看数据就知道是bfs可以水过的。

#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define STA 30000
int q[STA],d[STA],fa[STA],vis[STA],ans[STA];
int to[15][15],sw[15][15];
int n,k,s;
int bfs(int st){
   int l,r;
   l=r=0;
   int now=(1<<st)*10+st-1;
   q[r++]=now;
   fa[now]=-1;
   while(l<r){
      now=q[l++];
      int room=now%10+1,sta=now/10;
      if(room==n&&sta==(1<<n))return 1;
      int next;
      for(int i=1;i<=n;i++)if(!vis[now-room+i] && to[room][i] && sta&(1<<i)){
          next=now-room+i;
          vis[next]=1;
          d[next]=d[now]+1;
          fa[next]=now;
          q[r++]=next;
      }
      for(int i=1;i<=n;i++)if(i!=room && sw[room][i]){
          if(!(sta&(1<<i)) && !vis[(sta|(1<<i))*10+room-1]){
          next=(sta|(1<<i))*10+room-1;
          vis[next]=1;
          d[next]=d[now]+1;
          fa[next]=now;
          q[r++]=next;
          }
          else if(sta&(1<<i) && !vis[(sta^(1<<i))*10+room-1]){
          next=(sta^(1<<i))*10+room-1;
          vis[next]=1;
          d[next]=d[now]+1;
          fa[next]=now;
          q[r++]=next;
          }
      }
   }
   return 0;

}
int main(){
//freopen("input.in","r",stdin);freopen("output.out","w",stdout);
    int cs=1;
   while(scanf("%d%d%d",&n,&k,&s) &&n){
       int x,y;
       memset(to,0,sizeof to);
       memset(sw,0,sizeof sw);
       memset(vis,0,sizeof vis);
       memset(d,0,sizeof d);
       while(k--){
          scanf("%d%d",&x,&y);
          to[x][y]=to[y][x]=1;
       }
       while(s--){
          scanf("%d%d",&x,&y);
          sw[x][y]=1;
       }
       printf("Villa #%d\n",cs++);
       if(bfs(1)){
           int u=(1<<n)*10+n-1,dis;
           printf("The problem can be solved in %d steps:\n",dis=d[u]);
           for(int i=0;i<dis;i++){
              ans[i]=u;
              u=fa[u];
           }
           int lastroom=1,sta0=1<<1,room,sta;
           for(int i=dis-1;i>=0;i--){
              room=ans[i]%10+1;sta=ans[i]/10;
              if(room!=lastroom)printf("- Move to room %d.\n",room);
              else{
                 for(int j=1;j<=n;j++)if((sta0&(1<<j))!=(sta&(1<<j))){
                    if(sta0&(1<<j))printf("- Switch off light in room %d.\n",j);
                    else printf("- Switch on light in room %d.\n",j);
                    break;
                 }
              } 
              lastroom=room;sta0=sta;
           }
           printf("\n");
           
       }else printf("The problem cannot be solved.\n\n"); 
       
   }
   return 0;
}

F - Decoding Morse Sequences

我的做法是把所有单词的Morse码编进Trie树,在词尾标记访问次数,然后记忆化搜索。

#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
           
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define INF 200000000
           
typedef long long ll;
int ch[1000010][3],sz;
char morse[26][10]
={".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..",
"--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};      
char s[10100],word[25],mod[100];   
ll dp[10100];
int t[1000010];

void insert(char *s){
   char *p=s;
   int u=0;
   for(;*p!='\0';p++){
       int temp;
       if(*p=='.')temp=1;
       else temp=2;
       if(ch[u][temp]==-1)ch[u][temp]=++sz;
       u=ch[u][temp];
   }
   if(ch[u][0]==-1)ch[u][0]=++sz;
   u=ch[u][0];
   t[u]++;
}
ll dfs(int now){
   if(dp[now]>=0)return dp[now];
   ll &ans=dp[now];
   ans=0;
   int u=0,flag=1;
   for(int i=now;s[i];i++){
      int temp;
      if(s[i]=='.')temp=1;
      else temp=2;
      if(ch[u][temp]==-1)return ans;
      u=ch[u][temp];
      if(ch[u][0]!=-1)ans+=t[ch[u][0]]*dfs(i+1);
   }
   return ans;
}
int main(){
   //freopen("r.in","r",stdin);freopen("r.out","w",stdout);
   int T;
   scanf("%d",&T);
   while(T--){
      scanf("%s",s);
      int m;
      scanf("%d",&m);
      memset(ch,-1,sizeof ch);
      memset(t,0,sizeof t);
      sz=0;
      for(int i=0;i<m;i++){
         mod[0]='\0';
         scanf("%s",word);
         for(int j=0;word[j];j++)
            strcat(mod,morse[word[j]-'A']);
         insert(mod);
      }
      memset(dp,-1,sizeof dp);
      dp[strlen(s)]=1;
      dfs(0);
      printf("%lld\n",dp[0]);
   }
   return 0;
}
G - Fill the Cisterns!

二分答案,精度0.0005.

#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
           
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define INF 2000000
#define eps 5e-4
           
typedef long long ll;

struct cistern{
    double b,h,s;
}c[50010];
double v,hmax,hmin;          
int n; 

int cmp(cistern a,cistern b){return a.b<b.b;}

int cal(double dh){
   double vx=0;
   for(int i=0;i<n&&c[i].b<dh;i++){
      double t=min(c[i].b+c[i].h,dh);
      vx+=(t-c[i].b)*c[i].s;
   }
   if(vx<v)return -1;
   if(vx>v)return 1;
   return 0;
}
double search(double low,double hi){
   double mid;
   while(hi-low>eps){
      mid=(hi+low)/2.0;
      if(cal(mid)>=0)hi=mid;
      else low=mid;
   }
   return hi;
}
int main(){
    //freopen("r.in","r",stdin);freopen("r.out","w",stdout);
   int t;
   scanf("%d",&t);
   while(t--){
      scanf("%d",&n);
      double w,h,vmax;
      hmax=0;hmin=INF;
      vmax=0;
      for(int i=0;i<n;i++){
         scanf("%lf%lf%lf%lf",&c[i].b,&c[i].h,&w,&h);
         c[i].s=w*h;
         hmax=max(hmax,c[i].h+c[i].b);
         hmin=min(hmin,c[i].b);
         vmax+=c[i].s*c[i].h;
      }
      scanf("%lf",&v);
      if(vmax<v){
         printf("OVERFLOW\n");
         continue;
      }
      
      sort(c,c+n,cmp);
      double dh=search(hmin,hmax);
      printf("%.2lf\n",dh);
      
   }
   return 0;
}

H -  Horizontally Visible Segments
其实应该很快反应过来是线段树的……跟染色差不多的,每次询问一次更新一次,中间hash判重然后加边,最后暴力搜索得到 Triangle 个数。

有个细节是x,y在[0,8000],0<=n<=8000,建立的图应该是稀疏图,用vector存,所以一定要判重的!

#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>

#define rson o<<1|1
#define lson o<<1
#define H 16000
#define MOD 1403641

using namespace std;

vector <int> g[8010];
int col[16000<<2],y1,y2;

struct segment{
   int y1,y2,x;
}seg[8010];
struct Hash{
   int va;
   Hash *next;
   Hash(){va=-1;next=NULL;}
}hash[MOD];
void init(){
   for(int i=0;i<MOD;i++){hash[i].va=-1;hash[i].next=NULL;}
}
int exist(int u,int v){
   int x=u*10000+v;
   if(hash[x%MOD].va==-1){hash[x%MOD].va=x;return 0;}
   else{
        Hash *u=&hash[x%MOD];
        while(u->next!=NULL){
           if(u->va==x)return 1;
           u=u->next;
        }
        if(u->va==x)return 1;
        u->next=new Hash;
        u->next->va=x;u->next->next=NULL;
        return 0;
   }
}
int cmp(struct segment a,struct segment b){return a.x<b.x;}
void pushdown(int o,int l,int r){
    if(col[o]!=-1){
       col[rson]=col[lson]=col[o];
    }
}
void upd(int o,int l,int r,int u){
   if(y1<=l&&y2>=r){
      col[o]=u;
   }else if(y2>=l&&y1<=r){
      int mid=(l+r)>>1;
      pushdown(o,l,r);
      col[o]=-1;
      if(y1<=mid)upd(lson,l,mid,u);
      if(y2>mid)upd(rson,mid+1,r,u);
   }
}
void que(int o,int l,int r,int v){
   int mid=(l+r)/2;
   if(y1<=l&&y2>=r){
       if(col[o]==-1){
          que(lson,l,mid,v);
          que(rson,mid+1,r,v);
       }else if(col[o]&&!exist(v,col[o])){
             g[v].push_back(col[o]);
       }
   }else if(y2>=l&&y1<=r){
       pushdown(o,l,r);
       if(y1<=mid)que(lson,l,mid,v);
       if(y2>mid)que(rson,mid+1,r,v);
    }
}
int main(){
    int T,n;
    scanf("%d",&T);
    while(T--){
       scanf("%d",&n);
       for(int i=1;i<=n;i++)scanf("%d%d%d",&seg[i].y1,&seg[i].y2,&seg[i].x);
       sort(seg+1,seg+n+1,cmp);
       
       for(int i=1;i<=n;i++)g[i].clear();
       memset(col,0,sizeof col);
       init();
       for(int i=1;i<=n;i++){
           y1=seg[i].y1*2;y2=seg[i].y2*2;
           if(i>1)que(1,0,H,i);
           upd(1,0,H,i);
       }
       int cnt=0;
       for(int i=3;i<=n;i++)if(g[i].size()>1)
         for(int j=0;j<g[i].size();j++){
            int u=g[i][j];
            for(int k=0;k<g[u].size();k++)
              for(int q=0;q<g[i].size();q++)if(g[i][q]==g[u][k])cnt++;
         }
       
       printf("%d\n",cnt);
    }
    return 0;
}

J - (Your)((Term)((Project)))

细节题了,递归做最保险,把里面没有运算符的删掉之后,再每次找匹配的括号,判断删除否,两个括号中间的部分再递归。

#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
           
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define INF 200000000
#define SKIP(p) while(*p==' ')++p;
           
typedef long long ll;
char s[300],q[300];
int res;  
void solve(char *s,char *q){
    char *p;
    int sgn=1;
    for(p=s;p<=q;p++){
       if(*p=='+')sgn=1;
       else if(*p=='-')sgn=-1;
       else if(*p=='('){
         char *t;
         int cnt=1;
         for(t=p+1;t<=q;t++){
            if(*t=='(')cnt++;
            else if(*t==')')cnt--;
            if(!cnt)break;
         }
         if(sgn>0)*p=*t=' ';
         if(t-p>2)solve(p+1,t-1);
       }
    }
}      
void deal(char *p,int n){
   for(int i=0;i<n;i++)if(p[i]<='Z'&&p[i]>='A'){
      int l=i-1,r=i+1;
      while(l>=0&&r<n){
         if(p[l]!='('||p[r]!=')')break;
         p[l]=p[r]=' ';
         l--;r++;
      }
   }
   solve(p,p+n-1);
}
int main(){
   //freopen("r.in","r",stdin);freopen("r.out","w",stdout);
   int t;
   scanf("%d",&t);
   gets(s);
   while(t--){
      gets(s);
      char *p=s;
      res=0;
      for(;*p!='\0';p++){
         SKIP(p);
         q[res++]=*p;
      }
      deal(q,res);
      for(int i=0;i<res;i++)if(q[i]!=' ')
          printf("%c",q[i]);
      printf("\n");
   }
   return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值