Codeforces 417D Cunning Gena【排序+状压dp】
2016-10-25 23:03
417 查看
D. Cunning Gena
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output
A boy named Gena really wants to get to the "Russian Code Cup" finals, or at least get a t-shirt. But the offered problems are too complex, so he made an arrangement with his n friends
that they will solve the problems for him.
The participants are offered m problems on the contest. For each friend, Gena knows what problems he can solve. But Gena's friends
won't agree to help Gena for nothing: the i-th friend asks Gena xi rubles
for his help in solving all the problems he can. Also, the friend agreed to write a code for Gena only if Gena's computer is connected to at least ki monitors,
each monitor costs b rubles.
Gena is careful with money, so he wants to spend as little money as possible to solve all the problems. Help Gena, tell him how to spend the smallest possible amount of money. Initially, there's no monitors connected to Gena's computer.
Input
The first line contains three integers n, m and b (1 ≤ n ≤ 100; 1 ≤ m ≤ 20; 1 ≤ b ≤ 109) —
the number of Gena's friends, the number of problems and the cost of a single monitor.
The following 2n lines describe the friends. Lines number 2i and (2i + 1) contain
the information about the i-th friend. The 2i-th
line contains three integers xi, ki and mi (1 ≤ xi ≤ 109; 1 ≤ ki ≤ 109; 1 ≤ mi ≤ m) —
the desired amount of money, monitors and the number of problems the friend can solve. The (2i + 1)-th line contains mi distinct
positive integers — the numbers of problems that the i-th friend can solve. The problems are numbered from 1 to m.
Output
Print the minimum amount of money Gena needs to spend to solve all the problems. Or print -1, if this cannot be achieved.
Examples
input
output
input
output
input
output
题目大意:
一共有M个问题,有N个小伙伴可以帮你解决问题,其中一个监视器的金额为b。
对应接下来N组输入,对应每组输入两行,对应表示第i个小伙伴的信息,其中第一行包含三个元素,第一个元素表示雇佣这个小伙伴帮忙解决问题的花费,第二个表示这个小伙伴帮忙解决问题所需要的监视器的个数,第三个元素表示这个小伙伴能够解决的问题数。
(假如第一个小伙伴需要1个监视器,第二个小伙伴需要两个监视器,那么一共建立起来两个监视器就能同时满足两个条件)
接下来一行,表示能够解决问题的编号。
对应解决M个问题,求一个最小花费方案。
思路:
1、首先不考虑这个监视器的问题:
①对应观察到M只有20,那么我们可以对应设定dp【i】表示雇佣小伙伴解决了状态i时候的这些问题的最小花费。其中i=5.对应二进制表示:101,那么我们就能够表示5这个状态能够解决第一个和第三个问题,但是现在没有解决第二个问题。
②那么不难想到状态转移方程:dp【q】=min(dp【q】,dp【j】+a【i】.val)(其中对应第i个人能够解决状态q比状态j多出来的问题)
③对应解决上式状态转移方程,我们设定tmp【i】表示第i个人能够解决问题的状态,(例如tmp【1】=5,表示第1个人能够解决第一个和第三个问题,但是解决不了第二个问题。)那么我们此时第一层for枚举人,从0到n,然后第二层for枚举状态j,然后判断一下状态j下,有没有第i个人能够解决的问题并且状态j没有解决完的问题,对应判断:if(tmp【i】&j==tmp【i】)那么说明状态j已经解决了所有第i个人能够解决的问题,否则相反,并且我们同时设定q=j|a【i】;那么,dp【q】=min(dp【q】,dp【j】+a【i】.val);
此时状态转移过程最终结果dp【(1<<m)-1】就是解决了所有问题m所需要的最小雇佣花费。
2、那么此时考虑这个监视器问题;
①我们可以二分监视器个数,但是时间复杂度略高,可能会T
②我们其实直接将N个人按照需要监视器的个数从小到大排序即可,那么对应在将每个人都状态转移完毕之后,我们维护一次最小值:
ans=min(ans,dp【(1<<m)-1】+a【i】.yi*b),其中a【i】.yi表示当前这个人需要的监控器个数、这样保证前i个人进行了状态转移之后,当前这第i个人就是需要监控器个数最多的人,那么对应在雇佣的最小花费的基础上,维护一个最小总花费即可。
3、注意数组大小,注意数据范围,注意dp数组初始化大小,需要long long int的数据的地方不要忘记即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll __int64
#define inf 2000000000000000000
struct node
{
int xi;
ll yi,pos;
}a[1515];
int n,m;
ll b;
int tmp[151515];
ll dp[(1<<20)+15];
int cmp(node a,node b)
{
return a.yi<b.yi;
}
int main()
{
while(~scanf("%d%d%I64d",&n,&m,&b))
{
for(int i=0;i<(1<<m);i++)dp[i]=inf;
memset(tmp,0,sizeof(tmp));
for(int i=0;i<n;i++)
{
int k;
scanf("%d%I64d%d",&a[i].xi,&a[i].yi,&k);
while(k--)
{
int x;
scanf("%d",&x);
x--;
tmp[i]+=(1<<x);
}
a[i].pos=i;
}
sort(a,a+n,cmp);
dp[0]=0;
ll ans=inf;
for(int i=0;i<n;i++)
{
for(int j=0;j<(1<<m);j++)
{
int pos=a[i].pos;
if((j&tmp[pos])!=tmp[pos])
{
int q=j|tmp[pos];
dp[q]=min(dp[q],dp[j]+a[i].xi);
}
}
if(dp[(1<<m)-1]!=inf)
{
ans=min(dp[(1<<m)-1]+a[i].yi*b,ans);
}
}
if(ans==inf)printf("-1\n");
else
printf("%I64d\n",ans);
}
}
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output
A boy named Gena really wants to get to the "Russian Code Cup" finals, or at least get a t-shirt. But the offered problems are too complex, so he made an arrangement with his n friends
that they will solve the problems for him.
The participants are offered m problems on the contest. For each friend, Gena knows what problems he can solve. But Gena's friends
won't agree to help Gena for nothing: the i-th friend asks Gena xi rubles
for his help in solving all the problems he can. Also, the friend agreed to write a code for Gena only if Gena's computer is connected to at least ki monitors,
each monitor costs b rubles.
Gena is careful with money, so he wants to spend as little money as possible to solve all the problems. Help Gena, tell him how to spend the smallest possible amount of money. Initially, there's no monitors connected to Gena's computer.
Input
The first line contains three integers n, m and b (1 ≤ n ≤ 100; 1 ≤ m ≤ 20; 1 ≤ b ≤ 109) —
the number of Gena's friends, the number of problems and the cost of a single monitor.
The following 2n lines describe the friends. Lines number 2i and (2i + 1) contain
the information about the i-th friend. The 2i-th
line contains three integers xi, ki and mi (1 ≤ xi ≤ 109; 1 ≤ ki ≤ 109; 1 ≤ mi ≤ m) —
the desired amount of money, monitors and the number of problems the friend can solve. The (2i + 1)-th line contains mi distinct
positive integers — the numbers of problems that the i-th friend can solve. The problems are numbered from 1 to m.
Output
Print the minimum amount of money Gena needs to spend to solve all the problems. Or print -1, if this cannot be achieved.
Examples
input
2 2 1 100 1 1 2 100 2 1 1
output
202
input
3 2 5 100 1 1 1 100 1 1 2 200 1 2 1 2
output
205
input
1 2 1 1 1 1 1
output
-1
题目大意:
一共有M个问题,有N个小伙伴可以帮你解决问题,其中一个监视器的金额为b。
对应接下来N组输入,对应每组输入两行,对应表示第i个小伙伴的信息,其中第一行包含三个元素,第一个元素表示雇佣这个小伙伴帮忙解决问题的花费,第二个表示这个小伙伴帮忙解决问题所需要的监视器的个数,第三个元素表示这个小伙伴能够解决的问题数。
(假如第一个小伙伴需要1个监视器,第二个小伙伴需要两个监视器,那么一共建立起来两个监视器就能同时满足两个条件)
接下来一行,表示能够解决问题的编号。
对应解决M个问题,求一个最小花费方案。
思路:
1、首先不考虑这个监视器的问题:
①对应观察到M只有20,那么我们可以对应设定dp【i】表示雇佣小伙伴解决了状态i时候的这些问题的最小花费。其中i=5.对应二进制表示:101,那么我们就能够表示5这个状态能够解决第一个和第三个问题,但是现在没有解决第二个问题。
②那么不难想到状态转移方程:dp【q】=min(dp【q】,dp【j】+a【i】.val)(其中对应第i个人能够解决状态q比状态j多出来的问题)
③对应解决上式状态转移方程,我们设定tmp【i】表示第i个人能够解决问题的状态,(例如tmp【1】=5,表示第1个人能够解决第一个和第三个问题,但是解决不了第二个问题。)那么我们此时第一层for枚举人,从0到n,然后第二层for枚举状态j,然后判断一下状态j下,有没有第i个人能够解决的问题并且状态j没有解决完的问题,对应判断:if(tmp【i】&j==tmp【i】)那么说明状态j已经解决了所有第i个人能够解决的问题,否则相反,并且我们同时设定q=j|a【i】;那么,dp【q】=min(dp【q】,dp【j】+a【i】.val);
此时状态转移过程最终结果dp【(1<<m)-1】就是解决了所有问题m所需要的最小雇佣花费。
2、那么此时考虑这个监视器问题;
①我们可以二分监视器个数,但是时间复杂度略高,可能会T
②我们其实直接将N个人按照需要监视器的个数从小到大排序即可,那么对应在将每个人都状态转移完毕之后,我们维护一次最小值:
ans=min(ans,dp【(1<<m)-1】+a【i】.yi*b),其中a【i】.yi表示当前这个人需要的监控器个数、这样保证前i个人进行了状态转移之后,当前这第i个人就是需要监控器个数最多的人,那么对应在雇佣的最小花费的基础上,维护一个最小总花费即可。
3、注意数组大小,注意数据范围,注意dp数组初始化大小,需要long long int的数据的地方不要忘记即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll __int64
#define inf 2000000000000000000
struct node
{
int xi;
ll yi,pos;
}a[1515];
int n,m;
ll b;
int tmp[151515];
ll dp[(1<<20)+15];
int cmp(node a,node b)
{
return a.yi<b.yi;
}
int main()
{
while(~scanf("%d%d%I64d",&n,&m,&b))
{
for(int i=0;i<(1<<m);i++)dp[i]=inf;
memset(tmp,0,sizeof(tmp));
for(int i=0;i<n;i++)
{
int k;
scanf("%d%I64d%d",&a[i].xi,&a[i].yi,&k);
while(k--)
{
int x;
scanf("%d",&x);
x--;
tmp[i]+=(1<<x);
}
a[i].pos=i;
}
sort(a,a+n,cmp);
dp[0]=0;
ll ans=inf;
for(int i=0;i<n;i++)
{
for(int j=0;j<(1<<m);j++)
{
int pos=a[i].pos;
if((j&tmp[pos])!=tmp[pos])
{
int q=j|tmp[pos];
dp[q]=min(dp[q],dp[j]+a[i].xi);
}
}
if(dp[(1<<m)-1]!=inf)
{
ans=min(dp[(1<<m)-1]+a[i].yi*b,ans);
}
}
if(ans==inf)printf("-1\n");
else
printf("%I64d\n",ans);
}
}
相关文章推荐
- CodeForces 293 B.Distinct Paths(dfs+状压DP)
- Codeforces 743E(二分+状压dp)
- CF417D--- Cunning Gena(排序+状压dp)
- codeforces 16E 概率+状压dp
- Codeforces 864E Fire【排序+背包dp】
- Codeforces 454D Little Pony and Harmony Chest【思维+状压Dp+记录路径】好题!
- Codeforces 443D Andrey and Problem【排序+概率dp】
- codeforces 864E Fire (排序+背包dp)
- codeforces 698 C. LRU (概率与期望+状压DP)
- Codeforces 510D.Fox And Jumping By Assassin 数论+状压dp
- codeforces 13C Sequence(排序,DP)
- codeforces 212 C DP 递推 计数 破环
- CodeForces-729C-Road to Cinema(二分查找 贪心 排序)
- CodeForces - 22B Bargaining Table(暴力+dp)
- codeforces 721C (拓排 + DP)
- HDU 4758 Walk Through Squares && AC自动机+状压DP
- codeforces 538E E. Demiurges Play Again(博弈+树形dp)
- Codeforces 698A. Vacations (简单DP)
- codeforces 940E Cashback 有趣的dp
- codeforces 505C Mr. Kitayuta, the Treasure Hunter( dp 缩减规模 )