• 题解 比赛 match


    比赛 match

    Description

    有 N 支队伍打比赛。已知有如下条件:
    • 每支队伍恰好打了 4 场比赛
    • 对于一场比赛,如果是平局,双方各得 1 分;否则胜者得 3 分,负者不得分
    给定每支队伍的初始分数(这时候还没有发生任何比赛)。问编号为 1 的队伍在最优情况下的名次是多 少。

    Input

    输入的第一行有一个整数 N (5 ≤ N ≤ 50) 。
    接下来一行 N 个整数,依次描述编号为 1 ∼ N 的队伍的初始分数。

    Output

    输出一行一个整数,描述最优情况下,编号为 1 的队伍的名次。

    Sample Input

    50
    0 4 1 10 4 9 3 2 9 5 2 3 1 9 3 10 4 7 2 1 8 9 4 9 1 2 9 6 9 3 8 6 1 5 7 1 3 5 6 8 1 8 9 2 10 5 3 5 2 2

    Sample Output

    1

    解析

    这道题目盯着题解看了半个多小时硬是没看懂,所以决定自己写一篇...

    这道题可以考虑搜索,

    设当前状态为((x),(w),(l),(d)),

    其中(x)表示当前是第几队,

    (w)表示(1~(x)-1)中的队与( (x)~(n))中的队比赛赢了(w)场,(l)(s)也一样。

    那么,考虑状态转移,

    在每个阶段,考虑当前的队与前面的队(即1~(x)-1)的比赛情况和与后面的队的比赛情况

    开六重循环,逐个枚举(x)队赢的场数(i),输的场数(j),平的场数(k)

    以及与前面的队比赛的赢的场数(ni),输的场数(nj),平的场数(nk)

    那么,在转移(即搜索到(x)+1队)时,

    w就应该加上(i-ni)(因为赢了(减掉(ni)是因为这是对于前面的队(1~(x)-1)的影响,而不是对后面的)),

    再减去(nj)(因为和前面扯平了(别忘了(w)的含义,我们已经到了第(x)+1层)),

    (l),(d)也同理。

    而当(x)=(n)+1时,如果(w),(l),(d)都等于0,即当前状态可行,就返回0,

    并且设(f[x][opt][min][max][d])表示递归到(x)队,

    如果(opt)=1,则(min)表示(w),(max)表示(l),如果(opt)=0,就相反。(可以省空间,当然四维数组也可以)

    (d)就表示平局的次数。

    那么在枚举的时候更新就行了。

    另外,还有一个剪枝,

    (w)>4且(l)>4,或(d)>4时,可以直接返回INF,

    因为这种情况下,就表示在(1~x-1)中一定存在两个队对( x~n)中的两个队产生了影响,

    那么实际上,(1~x-1)中的这两个队的影响就可以相互抵消掉(即让他们两互相比赛) (口胡证明请自行理解下哈)

    那么,初始状态就让第一队全部获胜(即(2,4,0,0))就行了!

    还有什么不懂的看下代码吧(也可以在评论区里问):

    #include<bits/stdc++.h>
    using namespace std;
    
    inline int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return f*sum;
    }
    
    const int INF=0x3f3f3f3f;
    int n,a[100001];
    int f[51][2][5][501][5];
    
    int dfs(int x,int w,int l,int d){
    	if(x==n+1) return !w&&!l&&!d? 0:INF;
    	if((w>4&&l>4)||d>4) return INF;
    	int &ret=f[x][(w<l)][min(w,l)][max(w,l)][d];
    	if(ret+1) return ret;
    	ret=INF;
    	for(int i=0;i<=4;i++)/*x队的胜利次数*/{
    		for(int j=0;j<=4-i;j++)/*x队的失败次数*/{
    			int k=4-i-j;//x队的平局次数
    			for(int ni=0;ni<=min(l,i);ni++)/*x队与1~(x-1)队中比赛获胜的次数*/
    				for(int nj=0;nj<=min(w,j);nj++)/*x队与1~(x-1)队中比赛失败的次数*/
    					for(int nk=0;nk<=min(k,d);nk++)/*x队与1~(x-1)队中比赛平局的次数*/
    						ret=min(ret,dfs(x+1,w-ni+i-nj,l-nj+j-ni,d-nk+k-nk)+(a[x]+3*i+k>a[1]));
    		}
    	}
    	return ret;
    }
    
    int main(){
    	memset(f,-1,sizeof(f));
    	n=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	a[1]+=12;
    	printf("%d
    ",dfs(2,4,0,0)+1);
    	return 0;
    }
    
    
  • 相关阅读:
    MySQL学习笔记
    Git常用命令
    MacBook Pro m1安装swoole PHP版本7.4
    斐波那契数列实现的2种方法
    归纳一些比较好用的函数
    阶乘的实现
    冒泡排序
    PHP上传图片
    PHPStorm常用快捷键
    DataTables的使用
  • 原文地址:https://www.cnblogs.com/zsq259/p/10597263.html
Copyright © 2020-2023  润新知