首页 > ACM题库 > HDU-杭电 > HDU 3093-Parliament Seat-动态规划-[解题报告]HOJ
2014
03-01

HDU 3093-Parliament Seat-动态规划-[解题报告]HOJ

Parliament Seat

问题描述 :

It is election time. V voters attend the election, each casting their vote for one of N political parties. Mofficials will be elected into the parliament.
The conversion from votes to parliament seats is done using the D’Hondt method with a 5% threshold.More precisely, suppose that the parties are numbered 1 through N and that they receive V1, V2, …, VN votes. Parliament seats are allocated as follows:
1. All parties that receive strictly less than 5% of V votes are erased from the list of parties.
2. The parliament is initially empty i.e. every party has zero seats allocated.
3. For each party P, the quotient QP=VP/(SP+1) is calculated, where VP is the total number of votes received by party P, and SP is the number of seats already allocated to party P.
4. The party with the largest quotient QP is allocated one seat. If multiple parties have the same largest quotient, the lower numbered party wins the seat.
5. Repeat steps 3 and 4 until the parliament is full.
The votes are being counted and only part of the V votes has been tallied. It is known how many votes each party has received so far.Write a program that calculates for each party, among all possible outcomes of the election after all V votes are counted, the largest and smallest number of seats the party wins.

输入:

The first line contains the integers V, N and M (1 ≤ V ≤ 10,000,000, 1 ≤ N ≤ 100, 1 ≤ M ≤ 200), the numbers of votes, parties and seats in the parliament.
The second line contains N integers � how many votes (of those that have been counted) each party got. The sum of these numbers will be at most V.

输出:

The first line contains the integers V, N and M (1 ≤ V ≤ 10,000,000, 1 ≤ N ≤ 100, 1 ≤ M ≤ 200), the numbers of votes, parties and seats in the parliament.
The second line contains N integers � how many votes (of those that have been counted) each party got. The sum of these numbers will be at most V.

样例输入:

20 4 5
4 3 6 1
100 3 5
30 20 10

样例输出:

3 3 3 2
1 0 1 0	
4 3 3
1 1 0


Hint
In the first example 14 votes have been tallied and 6 are yet to be counted. To illustrate one possible outcome, suppose that the first party receives 2 of those 6 votes, the second none, the third 1 vote and the fourth 3 votes. The parties' totals are 6, 3, 7 and 4 votes. All parties exceeded the 5% threshold. Seats are allocated as follows: 1. The quotients are initially 6/1, 3/1, 7/1 and 4/1; the largest is 7/1 so party 3 wins a seat. 2. The quotients are 6/1, 3/1, 7/2 and 4/1; the largest is 6/1 so party 1 wins a seat. 3. The quotients are 6/2, 3/1, 7/2 and 4/1; the largest is 4/1 so party 4 wins a seat. 4. The quotients are 6/2, 3/1, 7/2 and 4/2; the largest is 7/2 so party 3 wins a seat. 5. The quotients are 6/2, 3/1, 7/3 and 4/2; parties 1 and 2 are tied with quotients 6/2 and 3/1,but party 1 is lower numbered so it wins the last seat. In this outcome, the numbers of seats won by the parties are 2, 0, 2 and 1. Since it is possible for the second party not to win any seats, the second number on the second line of output is zero.

思路:直接引用论文的话。

暂时先不考虑“使剩下的物品都放不下”的条件,那就是求 0-1 背包
的所有可行方案。
用 Fi[j]表示前 i 件物品中选若干件总体积为 j 的方案数,初始为 F0[0]=1,转移
方程是:
Fi[j] = Fi-1[j] (Vi>j)
Fi[j] = Fi-1[j] + Fi-1[j-Vi](j>=Vi)
 
显然这个算法的效率是 O(n*C)的,它计算了所有装放背包的方案数。
 
现在考虑“使剩下的物品都放不进去”的条件,如果剩下的物品中体
积最小为 v,那么方案数就是 sum{ Fn[j] }(C>=j>C-v)。前提是我们事先确定
了剩下中体积最小的是哪个。
对体积排序后,下一步就是枚举 i 作为剩余物品中体积最小的一件。对
于所有 s<i 的物品必须都要放入背包,对于 i 则不能放入背包,对于 s>i 的
物品做 0-1背包可行方案的统计,将sum{ Fn[j] }(C>=j>C-Vi)累加到 ans。
由于每次都需要对 n-i 件物品做统计,一共统计 n次,效率是 O(n2
*C)。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define Maxn 4000
using namespace std;
int v[Maxn],dp[10100],ans,Min,Sum;
int main()
{
    int t,n,m,i,j,Case=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        Sum=0;
        Min=0x7fffffff;
        for(i=1;i<=n;i++)
        {
            scanf("%d",v+i);
            Min=min(Min,v[i]);
            Sum+=v[i];
        }
        ans=0;
        int sum=0,f=0,k;
        sort(v+1,v+1+n);
        for(i=1;i<=n;i++)
        {
            memset(dp,0,sizeof(dp));
            dp[sum]=1;
            for(j=i+1;j<=n;j++)
            for(k=m;k>=sum+v[j];k--)
                dp[k]=dp[k]+dp[k-v[j]];
            for(j=m;j>=m-v[i]+1;j--)
            if(j>=sum) ans+=dp[j];
            sum+=v[i];
        }
        if(Sum<=m)
            printf("%d 1\n",++Case);
        else
            if(Min>m)
            printf("%d 0\n",++Case);
        else
        printf("%d %d\n",++Case,ans);
    }
    return 0;
}

 

参考:http://www.cnblogs.com/wangfang20/archive/2013/08/03/3234503.html


  1. L(X [0 .. M-1],Y [0 .. N-1])= 1 + L(X [0 .. M-2],Y [0 .. N-1])这个地方也也有笔误
    应改为L(X [0 .. M-1],Y [0 .. N-1])= 1 + L(X [0 .. M-2],Y [0 .. N-2])

  2. 有限自动机在ACM中是必须掌握的算法,实际上在面试当中几乎不可能让你单独的去实现这个算法,如果有题目要用到有限自动机来降低时间复杂度,那么这种面试题应该属于很难的级别了。