HDU 4281 Judges' response 状压dp+多旅行商问题

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4281

Judges' response

Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
#### 问题描述 > The contest is running and the judges is busy watching the progress of the contest. Suddenly, N - 1 (N <= 16) contestants hand up their hand at the same time. The judges should go to answer the contestants' question one by one. The judges already foresee that answering contest i's question would cost Ci minutes. In order to serve all the contestant, each judges is assigned to serve some subset of the contestants. As the judges have limited patience, each one of them can serve the contestants for no more than M minutes. >   You are asked to solve two problems: >   1. At least how many judges should be sent so that they can serve all the contestants? (Because the judges have limited patience, each one of them cannot serve too many contestants.) >   2. If there are infinite number of judges, how to assign the route for each judge so that the sum of their walking time is minimized? Each contestant i is reside in place (xi, yi), the judges are in place (x1, y1). Assuming the walking speed of the judge is 1.

输入

There are several test cases, Each case begin with two integer N, M(with the meaning in the above context, 2 <= N <= 16, 0 <= M <= 100000).
  Then N lines follow and line i will contain two numbers x, y(0 <= x, y <= 1000), indicating the coordinate of place i.
  Then another N lines follow and line i will contain numbers Ci(0 <= Ci <= 1000), indicating the time to solve contestant i's question. C1 will 0 as place 1 is for the judges.
  
  The distance between place i and place j is defined as ceil(sqrt((xi - xj) ^ 2 + (yi - yj) ^ 2)). (ceil means rounding the number up, e.g. ceil(4.1) = 5)

输出

  For each case, output two numbers. The first is the minimum number of judges for question 1. The second is the minimum sum of walking time for question 2.
  If it's impossible to serve all the contestants, please output -1 -1 instead.

样例输入

3 3
0 0
0 3
0 1
0
1
2

3 2
0 0
0 3
0 1
0
1
2

3 1
0 0
0 3
0 1
0
1
2
  
16 35
30 40
37 52
49 49
52 64
31 62
52 33
42 41
52 41
57 58
62 42
42 57
27 68
43 67
58 48
58 27
37 69
0
19
30
16
23
11
31
15
28
8
8
7
14
6
19
11

样例输出

1 6
2 8
-1 -1
8 467

题意

回答每个学生的问题需要ai的时间,每个助教的忍耐时间是m,一个助教接受的提问时间一定不能超过m,第一个问题是问最少需要多少个助教才能解决所有的学生的问题。第二个问题是说,给你助教的位置(第一个),和学生的位置,你现在有无限多的助教,这些助教解决完问题,最后要回到原先的点。问如何分配能使回答完所有的学生的问题之后所有的助教所走的路程总和最小。

题解

这题数据很小,可以考虑状压。
先把所有的总时间不超过m的学生的集合找出来,然后dp[i]表示接受状态为i的学生的问题需要最少的助教,j表示某个总和不超过m的子集,则有转移方程:dp[i]=min(dp[i],dp[i^j]+1)。
对于第二个问,我们也可以用第一个问题的方法来做dp2[i][0]表示走了状态为i的点,最后回到原来位置的最少路程,则,用这些子集(上个问就已经处理出来的那些集合),就能拼出走完所有的点所走的最短路程。

代码

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf

typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;

const int INF=0x3f3f3f3f;
const LL INFL=10000000000000000LL;
const double eps=1e-9;

const double PI = acos(-1.0);

//start----------------------------------------------------------------------

const int maxn=17;

PII pt[maxn];
int arr[maxn];
int n,m;
VI vec;
int dp[1<<maxn];
int dp2[1<<maxn][maxn];

int dis(int i,int j) {
    int x=pt[i].X-pt[j].X;
    int y=pt[i].Y-pt[j].Y;
    return ceil(sqrt(x*x+y*y));
}

void tsp(int dp[][maxn]) {
    rep(i,0,(1<<maxn)) rep(j,0,maxn) dp[i][j]=INF;

    dp[1][0]=0;
    rep(i,2,(1<<n)) {
        rep(j,0,n) {
            if(!(i&(1<<j))) continue;
            rep(k,0,n) {
                if(k==j||(i&(1<<k))==0) continue;
                dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+dis(k,j));
            }
        }
    }
    rep(t,0,vec.sz()) {
        int i=vec[t];
        if((i&1)==0) continue;
        rep(j,1,n) {
            dp[i][0]=min(dp[i][0],dp[i][j]+dis(0,j));
        }
    }
}

void init() {
    vec.clear();
}

int main() {
    while(scf("%d%d",&n,&m)==2&&n) {

        init();

        rep(i,0,n) scf("%d%d",&pt[i].X,&pt[i].Y);
        rep(i,0,n) scf("%d",&arr[i]);

        rep(i,1,(1<<n)) {
            int sum=0;
            rep(j,0,n) {
                if(!(i&(1<<j))) continue;
                sum+=arr[j];
            }
            if(sum<=m) vec.pb(i);
        }

        rep(i,0,(1<<n)) dp[i]=INF;
        dp[0]=0;
        rep(i,0,(1<<n)) {
            rep(j,0,vec.sz()) {
                if((i|vec[j])!=i) continue;
                dp[i]=min(dp[i],dp[i^vec[j]]+1);
            }
        }

        int ans1=dp[(1<<n)-1];

        if(ans1>=INF){
            prf("-1 -1\n"); continue;
        }

        tsp(dp2);

        rep(i,0,(1<<n)) dp[i]=INF;
        dp[0]=0;
        rep(i,0,(1<<n)) {
            rep(j,0,vec.sz()) {
                if((i|vec[j])!=i) continue;
                dp[i]=min(dp[i],dp[i^vec[j]]+dp2[1|vec[j]][0]);
            }
        }

        int ans2=dp[(1<<n)-1];

        prf("%d %d\n",ans1,ans2);

    }
    return 0;
}

//end-----------------------------------------------------------------------
posted @ 2016-10-30 20:49  fenicnn  阅读(170)  评论(0编辑  收藏  举报