AtCoder Beginner Contest 204(补题)

C - Tour

AtCoder Beginner Contest 204(补题)_第1张图片AtCoder Beginner Contest 204(补题)_第2张图片AtCoder Beginner Contest 204(补题)_第3张图片
题意: 给个有向图,问你有多少对点,可以作为起点和终点,作为起点和终点,意味着可以从起点到终点。
思路: 直接从每个点 dfs一遍,看能到达的点有多少个,直接加起来即可。

#include<bits/stdc++.h>
using namespace std;
const int N=2010;
int e[N],h[N],ne[N],idx;
int n,m;
bool st[N];
void add(int a,int b) {
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u) {
    if(st[u]) return ;
    st[u]=1;
    for(int i=h[u];i!=-1;i=ne[i]) {
        int j=e[i];
        dfs(j);
    }
}
int main() {
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof(h));
    for(int i=0;i<m;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    int res=0;
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) {
            st[j]=0;
        }
        dfs(i);
        for(int j=1;j<=n;j++) {
            if(st[j]) {
                res++;
            }
        }
    }
    printf("%d\n",res);
    return 0;
}

D - Cooking

AtCoder Beginner Contest 204(补题)_第4张图片
AtCoder Beginner Contest 204(补题)_第5张图片
AtCoder Beginner Contest 204(补题)_第6张图片
题意: 有n个菜,做每个菜需要Ti时间,但是做每个菜需要用锅,每个锅一次只能做一个菜,现在只有2个锅,问最少用多长时间就能做完所有菜。
思路: 因为只有两个锅,需要把所有的菜,分成两组,所有菜的时间是固定的,所以不用考虑做菜顺序总做菜时间就是把所有的时间加起来,这也是固定的,定为sum
最好的情况就是两个组的总做菜时间都是sum/2,两个组中做菜时间长的那个定为A,短的定为B,最后输出的最少时间,是取决于A的,因为就算B结束了,A没结束,做菜就没结束。所以sum=A+B,找到最小的A,且A必须要大于等于(>=)sum/2,否则,大的那个就是B了,就要互换了。
要想找到最大的A,就需要知道做前n个菜,可以能出现的所有做菜时间(现在不论大小情况了,A和B的情况都列出来)
这就需要列个dp方程了,dp(i,j)代表考虑前i个菜的情况下,能出现的做菜时间是j,是否存在,这里的dp[i][j]定义为bool类型就行,代表j这个时间存不存在。
最后直接遍历dp[n][i]即可,找到大于等于sum/2的最小值。
这里还有注意奇数做除法向下取整的问题。

 dp[0][0]=1;
    for(int i=0;i<n;i++) {
        for(int j=0;j<=sum;j++) {
            //当前,前i个物品,可以消耗时间j
            if(dp[i][j]) { 
                 //第i+1个菜,A不做,放到B组,
                dp[i+1][j]=1; 
                //第i+1个菜,A做,B不做
                dp[i+1][j+a[i+1]]=1;
            }
        }
    }
#include<bits/stdc++.h>
using namespace std;
const int N=110,M=1e5+10;
int n;
int a[N];
bool dp[N][M];

int main() {
    scanf("%d",&n);
    int sum=0;
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    dp[0][0]=1;
    for(int i=0;i<n;i++) {
        for(int j=0;j<=sum;j++) {
            if(dp[i][j]) {
                dp[i+1][j]=1;
                dp[i+1][j+a[i+1]]=1;
            }
        }
    }
    int mid;
    if(sum%2==0) {
        mid=sum/2;
    }
    else {
        mid=sum/2+1;
    }
    for(int i=mid;i<=sum;i++) {
        if(dp[n][i]) {
            printf("%d\n",i);
            break;
        }
    }
    return 0;
}

To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激

你可能感兴趣的:(AtCoder,动态规划,dfs,AtCoder)