【动态规划】武器分配

来源:互联网 发布:网络语言单词词缀 编辑:程序博客网 时间:2024/04/23 17:29
描述 Description
    后勤部队运来一批武器(机枪和盔甲)。你要把这些武器分配给手下的marine们(每人一部机枪,一套盔甲)。可是问题来了。。。
    这些武器的型号不相同(武器是由出价最低的承包商制造的),把一部m型的机枪和一套n型的盔甲分配给一个marine得到的不满意值为(m-n)^2(每个marine当然希望自己得到的武器是同一型号的)。
    你的任务就是把a部机枪和b套盔甲分配给手下n个marine。使他们的不满意值之和最小。
输入格式 Input Format
第一行:3 个正整数 n , a , b (1<=n<=a,b<=80)
第二行:a 个数表示每部机枪的型号
第三行:b 个数表示每套盔甲的型号
0<=型号值<=10000
输出格式 Output Format
输出一个数:最小不满意值。
样例输入 Sample Input [复制数据]
样例输出 Sample Output [复制数据]
时间限制 Time Limitation

各个测试点1s


这个直接是没法动规的,要用点小小的数学知识来消除后效性。


考虑上下各两个,我们先把上下分别升序排,无非是X和||,

前者代价为A=(a[1]-b[2])^2+(a[2]-b[1])^2,

后者代价为B=(a[1]-b[1])^2+(a[2]-b[2])^2,

A - B = 2(a[1]b[1]+a[2]b[2])-2(a[1]b[2]+a[2][1])。

根据排序不等式A>B


所以可知,不可能有交叉。至此就消除了后效性。动规就很简单了。

只是初值要注意,f[0][0][i] 和 f[0][i][0] 都要赋值为0,因为不管是上面还是下面为0,都不可能有匹配的,但是其它状态又会从这两种情况转移而来。


#include <cstdio>#include <cstring>#include <string>#include <algorithm>using std::sort;#define min(a,b) ((a)<(b)?(a):(b))long aa[100];long bb[100];long f[100][100][100];long getint(){long rs=0;bool sgn=1;char tmp;do tmp = getchar();while (!isdigit(tmp)&&tmp-'-');if (tmp == '-'){tmp=getchar();sgn=0;}do rs=(rs<<3)+(rs<<1)+tmp-'0';while (isdigit(tmp=getchar()));return sgn?rs:-rs;}int main(){freopen("weapon.in","r",stdin);freopen("weapon.out","w",stdout);long n = getint();long a = getint();long b = getint();for (long i=1;i<a+1;i++){aa[i] = getint();}for (long j=1;j<b+1;j++){bb[j] = getint();}sort(aa+1,aa+a+1);sort(bb+1,bb+b+1);memset(f,0x3f,sizeof f);for (long i=0;i<a+1;i++)f[0][i][0] = 0;for (long j=0;j<b+1;j++)f[0][0][j] = 0;for (long k=1;k<n+1;k++){for (long i=1;i<a+1;i++){for (long j=1;j<b+1;j++){f[k][i][j] = min(f[k][i][j],f[k][i-1][j]);f[k][i][j] = min(f[k][i][j],f[k][i][j-1]);f[k][i][j] = min(f[k][i][j],f[k-1][i-1][j-1]+(aa[i]-bb[j])*(aa[i]-bb[j]));}}}long ans = 0x3f3f3f3f;for (long i=a;i>0;i--){for (long j=b;j>0;j--){ans = ans<f[n][i][j]?ans:f[n][i][j];}}printf("%ld",ans);return 0;}