腾讯俱乐部ACM训练赛进阶组题解

比赛链接:http://acm.hdu.edu.cn/diy/contest_show.php?cid=18010

problem1001

Meepo’s Problem I

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/65536K (Java/Other)
Total Submission(s) : 249   Accepted Submission(s) : 77
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

Most boys of TICers like play dota. Among these heroes there is a hero called Meepo. Meepo the Geomancer is a mischievous spirit of the earth who enjoys burying his enemies alive in mountains of rock spikes. We all know that Meepo can summon some duplicate of himself, the clones are independent to each other and have the same abilities as Meepo.
2012.11.11is Meepo's Mother's Grandmother's 1111th birthday(I don't know why= =), Meepo wants visit her, and there is an argument between two clones.
“Mother's Grandmother and Grandmother's Mother's are the same person.” one says.
“No, you're wrong......” other says.
“I'm right! Because Grandfather's father's and father's Grandfather are same person!” The first one says.
Meepo's clones are imperfect, so they don't know which one is right and ask for you to solve this problem.

Input

First line T, indicates the cases number T<=100.
  Then two string, s1 and s2, each one describes a person.
  All string's length <= 10000.
  String is only consisted of 6 elements :
1.  'A' : denote father.
2.  'B' : denote mother.
3.  'C' : denote grandmother.
4.  'D' : denote grandfather.
5.  'E' : denote maternal grandmother (mother's mother).
6.  'F' : denote maternal grandfather (mother's father).

Output

If two string describe same person print YES, otherwise print NO.

Sample Input

  3
  AD
  DA
  BC
  CA
  AB
  BA

Sample Output

  YES
  NO
  NO

Author

TIC
//
MYCode:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAX 20010
char str1[MAX];
char str2[MAX];
int st1[MAX];
int st2[MAX];
void solve(char str[MAX],int st[MAX])
{
    int len=strlen(str);
    int ct=1;
    int i;
    for(i=0;i<len;i++)
    {
        switch(str[i])
        {
            case 'A':
                st[ct++]=0;
                break;
            case 'B':
                st[ct++]=1;
                break;
            case 'C':
                st[ct++]=0;
                st[ct++]=1;
                break;
            case 'D':
                st[ct++]=0;
                st[ct++]=0;
                break;
            case 'E':
                st[ct++]=1;
                st[ct++]=1;
                break;
            case 'F':
                st[ct++]=1;
                st[ct++]=0;
                break;
        }
    }
    st[0]=ct-1;
}

int  main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        getchar();
        scanf("%s%s",&str1,&str2);
        solve(str1,st1);
        solve(str2,st2);
        int i;
        if(st1[0]!=st2[0])
        printf("NO\n");
        else
        {
            bool flag=true;
            for(i=1;i<=st1[0];i++)
            {
                if(st1[i]!=st2[i])
                {
                    flag=false;
                    break;
                }
            }
            if(flag==true)
            {
                printf("YES\n");
            }
            else
            printf("NO\n");
        }
    }
}

//
思路:
分别记录两个字符串的路径,然后进行比对.
problem 1002:

Dota

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 73   Accepted Submission(s) : 36
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

As we all know,JS is an excellent Dota player.Now he is facing with a difficult problem in the game. He has n different game equipements, and he want to sell all of them to n different player,one equipement for each player. However the different player would spend different price to buy the same equipement(for example player A is willing to spend 100 RMB in buying a equipment called \"Angel\'s Wings\" while player B is willing to spend 90 RMB in buying it). So please help JS determine how much money he can get at most if he sell all of his game equipements to the others.

Input

Input consists of multiple test cases. The first line of input contains a positive integer T, the number of test cases.Each test case consists of
n+1 lines. The first line is an integer n(1<=n<=100),which means there are n game equipements and n different players,both of them can be numbered
from 1 to n. Then fllowing 2th to (n+1)th line, each line contains n positive integers,the jth integer in the (i+1)th line means that the ith player
is willing to buy the jth equipement at this price.

Output

For each test case, you just output a single line which only contains an integer indicating how much money JS can get at most if he sell all of his game equipements to the others.We make sure that the result can be stored in a 32 bit signed integer. Please remember that each player can only buy one equipement of JS.

Sample Input

2
1
100
2
10 20
12 21

Sample Output

100
32

Author

TIC
//
最大权值完全匹配
转化成最小费用最大流.
把一条边的费用置为负值,求出最小费用就是原来的最大费用.构图过程不会有负环出现.
 
problem 1004:

Couple Game

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 302   Accepted Submission(s) : 53
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

Jiangshan and Yiran is a couple. Mengmeng and Sicong, Zhirui and Shimei and someother are the same as them. Now they participate in a game. In the game, N couples are standing in a circle, numbered consecutively, clockwise from 1 to 2N. Couple like Jiangshan and Yiran do not always stand together. The Couple who stand together can be remove and they can go to date immediately. For example, We remove Mengmeng and Sicong and other couples who stand together, until the circle is empty or we can't remove a couple any more. What we want to know is whether we can remove all the couples out of the circle?

(Hint:While submitting the code, choose the Microsoft Visual C++ compiler, or you might get an TLE.)

Input

There may be several test cases in the input file. In each case, the first line is an integer N(1 <= N <= 100000)----the number of couples. In the following N lines, each line contains two integers ---- the numbers of each couple.N = 0 indicates the end of the input.

Output

Output "Yes" if we can remove all the couples out of the circle. Otherwise, output "No".

Sample Input

4
1 4
2 3
5 6
7 8

Sample Output

Yes

Author

TIC
MYCode:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAX 200010
int st[MAX];
int match[MAX];
int n;
bool solve()
{
    int head,tail;
    head=tail=0;
    st[tail++]=1;
    int i;
    for(i=2;i<=2*n;i++)
    {
        if(match[st[tail-1]]==i)
        tail--;
        else
        st[tail++]=i;
    }
    if(head==tail)
    return true;
    return false;
}
int main()
{
    while(scanf("%d",&n))
    {
        if(n==0)
        break;
        int i;
        int a,b;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&a,&b);
            match[a]=b;
            match[b]=a;
        }
        if(solve())
        {
            printf("Yes\n");
        }
        else
        printf("No\n");
    }
}

//

栈的应用,开始的时候递归实现导致栈溢出.

 problem 1005:

Crazy review

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 50   Accepted Submission(s) : 18
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

Well , the exam is coming in a week. Poor Sweetsc has just H ( 0<= H <= 500) hours to review his N (1<=N<=20) courses. For the i-th course, if he go to the exam without any reviewing , he will get an initial score Si(0<=Si<=100) , If he spends one hour on this course , his score in this course will increase Vi(0<=Vi<=100) ; To simplify the problem , we assume you must spend a whole hour on courses. And it's useless if you spend less than 1 hour on any course.

As we see, some courses are easy to learn, but hard to master, while others are not; For each course, if you spend one hour on it, the next hour Vi will increase Dvi ( | Dvi | <=10); if Vi+Dvi is negative, Vi will become zero and never change. In this condition, no matter how hard Sweetsc learn the course, his score will never rise.

Because of some reasons (absent , unfinished homework) , There is an upper bound score Ui for every course . If Sweetsc's score reach the upper bound , his score will be the upper bound and never rise.

To make the description more clear , There is a chart for Si = 30. Vi = 20, Dvi = -5 and Ui = 70

Time 0 1 2 3 4 5 6 7 8
Score 30 50 65 70 70 70 70 70 70
Vi 20 15 10 5 0 0 0 0 0

Write a program to help sweet to pass all exams (in other words , get >= 60 scores in all exams). If he will fail in one or more courses, just print “POOR SWEETSC” (without quote). Otherwise, find an optimal average score he can get (ROUND TO THE NEAREST INTEGER)

Input

The first line contains two integers N, H.
Then following N lines. Each line include exactly 4 integers. Si,Vi,Dvi,and Ui.

Output

If Sweetsc could not pass all exams , output “POOR SWEETSC”; Otherwise, output an integer which is the optimal average score.
Round the average to the nearest integer.

Sample Input

2 5
10 30 -5 70
40 20 5 100

Sample Output

83

Author

TIC

 

MYCode:
 
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAX 25
int v[MAX];
int s[MAX];
int d[MAX];
int u[MAX];
int sum[MAX][510];
int n,h;
int ans;
int tot;
void make()
{
    int i,j;
    for(i=1;i<=n;i++)
    {
        sum[i][0]=s[i];
        for(j=1;j<=h;j++)
        {
            int add=v[i]+(j-1)*d[i];
            if(add<0)
            add=0;
            sum[i][j]=sum[i][j-1]+add;
            if(sum[i][j]>u[i])
            sum[i][j]=u[i];
        }
    }
}
void dfs(int cur,int time)
{
    if(cur==n+1)
    {
        if(tot>ans)
        ans=tot;
        return;
    }
    int i;
    for(i=1;i<=h && i<=time;i++)
    {
        if(sum[cur][i]>=60)
        {
            tot+=sum[cur][i];
            dfs(cur+1,time-i);
            tot-=sum[cur][i];
        }
        if(sum[cur][i]>=u[cur])//note
        break;
    }
}
int main()
{
    while(scanf("%d%d",&n,&h)!= EOF)
    {
        int i;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&s[i],&v[i],&d[i],&u[i]);
        }
        make();
        ans=-1;
        tot=0;
        dfs(1,h);
        if(ans!=-1)
        printf("%d\n",(int)(ans*1.0/n+0.5));
        else
        printf("POOR SWEETSC\n");
    }
}
//
先处理处在每门课花费一定时间所能取得的分数,然后DFS搜索,注意剪枝.
 
problem 1006:

传送装置

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 82   Accepted Submission(s) : 21
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

Sue 是一个有些奇怪的人. 当他从寝室出发到别的地方去的时候总想走回来. 但他不能准确的知道自己是否能够做到. 他发明了一个神奇的传送装置,这个传送装置可以传送m条不可逆的指定路线,每条传送路线都有一定的能源值耗费,不幸的是,Sawscanpy不希望Sue能够回到寝室,于是他计划干扰这个传送装置,Sawscanpy拥有的能源有限,他只能破坏一些传送路线,具体来说,Sawscanpy拥有一个能源值,他能够破坏能源值耗费小于等于他拥有的能源值的传送路线,在这过程中Sawscanpy拥有的能源值会损耗路线相应的能量值耗费,现在Sawscanpy想让你帮助他计算他需要拥有的能源值的最小值,使得Sue无法从寝室走出去或者从寝室走出去就走不回来了.

Input

输入包括多组测试数据
每组输入数据第一行包括3个整数n(1<=n<=100),m(0<=m<=n*n),s(1<=s<=n)。n 是地点的数目,m是传送路线的数目,s代表Sue所在寝室的编号,接下来m行每行3个整数 u, v, w,表示有一条不可逆的传送路线从u到v并且这条传送路线的能源值耗费是w(0<u, v, w<=100)。

Output

对于每组测试数据,输出一行一个整数 a 表示Sawscanpy需要拥有的能源值的最小值,如果他不需要拥有能源,值需要输出"Poor Sue"。

Sample Input

5 7 1
1 4 2
4 5 3
5 1 1
5 3 1
1 2 1
2 3 4
3 1 3
3 3 1
1 2 1
2 3 4
3 2 5

Sample Output

3
Poor Sue

Author

TIC
//
MYCode:

#include<iostream>
using namespace std;
#define MAX 10010
#define INFINITY 1000000000
int n,m;
struct edge
{
 int cap;
 int flow;
 int ver;
 edge*next;
 edge*rev;
};
edge edges[2*MAX+1];
edge* link[MAX+1];
int dist[MAX +1];
int h[MAX + 1];

int num;
int total_flow;
int min(int a,int b){return a < b?a:b;};
void add(int start,int end,int c)
{
 num++;
 edges[num].ver = end;
 edges[num].cap = c;
 edges[num].next = link[start];
 link[start] = edges + num;
 num++;
 edges[num].ver = start;
 edges[num].cap = 0;
 edges[num].next = link[end];
 link[end] = edges + num;
 link[start]->rev = link[end];
 link[end]->rev = link[start];
}

int sap(int n,int src,int des)
{
 edge* cur_edges[MAX+1];
 edge* rev_path[MAX+1];
 total_flow = 0;
 int i;
 for(i = 1; i <= n ;i++)
 cur_edges[i] = link[i];
 int argu_flow = INFINITY;
 int u = src;
 while(dist[src] < n)
 {
  if(u == des)
  {
   for(i = src; i != des;i = cur_edges[i]->ver)
   argu_flow = min(argu_flow,cur_edges[i]->cap);
   for(i = src; i != des ;i = cur_edges[i]->ver)
   {
    cur_edges[i]->cap -= argu_flow;
    cur_edges[i]->rev->cap += argu_flow;
    cur_edges[i]->flow += argu_flow;
    cur_edges[i]->rev->flow -= argu_flow;
   }
   total_flow += argu_flow;
   u = src;
  }
  edge* e;
  for(e = cur_edges[u];e; e = e->next)
  if(e->cap > 0 && dist[u] == dist[e->ver] + 1)
  break;
  if(e)
  {
   cur_edges[u] = e;
   rev_path[e->ver] = e->rev;
   u = e->ver;
  }
  else
  {
   if(--h[dist[u]] == 0)
   break;
   cur_edges[u] = link[u];
   int mini_dist = n;
   for(edge* e =  link[u]; e; e = e->next)
   if(e->cap > 0)
   mini_dist = min(mini_dist,dist[e->ver]);
   dist[u] = mini_dist + 1;
   h[dist[u]]++;
   if(u != src)
   u = rev_path[u]->ver;
  }
 }
 return total_flow;
}
void rev_bfs(int n,int src,int des)
{
 int q[MAX + 1];
 int head = 0;
 int tail = 0;
 for(int i = 1; i <= n; i++)
 {
  dist[i] = MAX;
  h[i] = 0;
 }
 q[tail++] = des;
 dist[des] = 0;
 h[0] = 1;
 int p;
 while(tail != head)
 {
  p = q[head++];
  for(edge* e = link[p];e;e = e->next)
  {
   if(dist[e->ver] != MAX ||e->rev->cap == 0)
   continue;
   dist[e->ver] = dist[p] + 1;
   h[dist[e->ver]]++;
   q[tail++] = e->ver;
  }
 }
}

 


int main()
{
    int src,des;
 while(cin>>n>>m>>src)
 {
  memset(link,0,sizeof(link));
  num = 0;
  int start,end,c;
  int des=n+1;
  while(m--)
  {
   cin>>start>>end>>c;
   //add(start,end,c);
   if(end!=src)
   {
                add(start,end,c);
            }
            else
            add(start,des,c);
  }
  rev_bfs(n+1,src,des);
  sap(n+1,src,des);
  if(total_flow!=0)
  printf("%d\n",total_flow);
  else
  printf("Poor Sue\n");
 }
}

//

增加一个附加汇点,将指向源点的边转而指向汇点,然后求出最大流就是答案.

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值