题目

题目大意

工厂内每个人只会操作一些机器。

他们会以随机的顺序来,每次选任意一台机器来操作。

一台机器只能由一个工人来操作。

可以花费一的代价来使某个工人学会一种机器。

问花费最少的代价,使得在所有的情况下每个人都能操纵一台机器。


正解

这题可以转化成个二分图。而答案一定满足:所有联通块都是个完全二分图。

我们要用最少的代价来造出这样的二分图。

预处理出所有的联通块,每个联通块用\((x,y)\)表示,意味着左边有\(x\)个,右边有\(y\)个。

于是就有了下面这个状压DP:\(f_{S,i}\)表示\(S\)集中的联通块都被使用了,其中完成了的联通块的\(x\)之和为\(i\)的最小边数。

等等,这个状态会不会存不下?

实际上,对于相同的\((x,y)\),我们只关心数量,所以可以进一步压缩。然后状态的数量就变得少了很多。

最后的答案记得要减去原来就有的边数。


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 33
inline void update(int &x,int y){x>y?x=y:0;}
int n;
char can[N][N];
bool vis[N][2];
int cntl,cntr,have;
void find(int x,bool k){
vis[x][k]=1;
if (k==0){
cntl++;
for (int i=1;i<=n;++i)
if (can[x][i]=='1' && !vis[i][1])
find(i,1);
}
else{
cntr++;
for (int i=1;i<=n;++i)
if (can[i][x]=='1' && !vis[i][0])
find(i,0);
}
}
int sc[N][N];
struct State{
int x,y;
int num;
} lis[N];
int m;
int pro[N];
int chose[N];
int f[200000][N];
void dfs(int k,int s,int x,int y){
if (k>m){
if (s==0)
f[0][0]=0;
for (int j=0;j<n;++j){
if (x==y)
update(f[s][x],f[s][j]+(x-j)*(x-j));
for (int i=1;i<=m;++i)
if (chose[i]<lis[i].num)
update(f[s+pro[i-1]][j],f[s][j]);
}
return;
}
for (int i=0;i<=lis[k].num;++i){
chose[k]=i;
dfs(k+1,s+i*pro[k-1],x+i*lis[k].x,y+i*lis[k].y);
}
}
int main(){
freopen("factory.in","r",stdin);
freopen("factory.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;++i){
scanf("%s",can[i]+1);
for (int j=1;j<=n;++j)
if (can[i][j]=='1')
have++;
}
for (int i=1;i<=n;++i){
if (!vis[i][0]){
cntl=cntr=0;
find(i,0);
sc[cntl][cntr]++;
}
if (!vis[i][1]){
cntl=cntr=0;
find(i,1);
sc[cntl][cntr]++;
}
}
pro[0]=1;
for (int i=0;i<=n;++i)
for (int j=0;j<=n;++j)
if (sc[i][j]){
lis[++m]={i,j,sc[i][j]};
pro[m]=pro[m-1]*(sc[i][j]+1);
}
memset(f,127,sizeof f);
f[0][0]=0;
dfs(1,0,0,0);
printf("%d\n",f[pro[m]-1][n]-have);
return 0;
}

总结

居然还有如此鬼畜的DP……

[JZOJ6299] 2019.08.12【NOIP提高组A】工厂的更多相关文章

  1. 2018.12.08【NOIP提高组】模拟B组总结(未完成)

    2018.12.08[NOIP提高组]模拟B组总结 diyiti 保留道路 进化序列 B diyiti Description 给定n 根直的木棍,要从中选出6 根木棍,满足:能用这6 根木棍拼出一个 ...

  2. 2017.08.08【NOIP提高组】模拟赛B组

    Summary 今天的题目也不算很难,唯一一道没做出来的题目是以前做过的,太不应该了. Problem T1 油滴扩展 题目大意 给你一堆点,你准备要在这么多的点当中滴油.你可以自己安排顺序,每次滴油 ...

  3. 2018.12.30【NOIP提高组】模拟赛C组总结

    2018.12.30[NOIP提高组]模拟赛C组总结 今天成功回归开始做比赛 感觉十分良(zhōng)好(chà). 统计数字(count.pas/c/cpp) 字符串的展开(expand.pas/c ...

  4. NOIP提高组2004 合并果子题解

    NOIP提高组2004 合并果子题解 描述:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消 ...

  5. [NOIP提高组2018]货币系统

    [TOC] 题目名称:货币系统 来源:2018年NOIP提高组 链接 博客链接 CSDN 洛谷博客 洛谷题解 题目链接 LibreOJ(2951) 洛谷(P5020) 大视野在线评测(1425) 题目 ...

  6. NOIP提高组初赛难题总结

    NOIP提高组初赛难题总结 注:笔者开始写本文章时noip初赛新题型还未公布,故会含有一些比较老的内容,敬请谅解. 约定: 若无特殊说明,本文中未知数均为整数 [表达式] 表示:在表达式成立时它的值为 ...

  7. 津津的储蓄计划 NOIp提高组2004

    这个题目当年困扰了我许久,现在来反思一下 本文为博客园ShyButHandsome的原创作品,转载请注明出处 右边有目录,方便快速浏览 题目描述 津津的零花钱一直都是自己管理.每个月的月初妈妈给津津\ ...

  8. 计蒜客 NOIP 提高组模拟竞赛第一试 补记

    计蒜客 NOIP 提高组模拟竞赛第一试 补记 A. 广场车神 题目大意: 一个\(n\times m(n,m\le2000)\)的网格,初始时位于左下角的\((1,1)\)处,终点在右上角的\((n, ...

  9. 1043 方格取数 2000 noip 提高组

    1043 方格取数  2000 noip 提高组 题目描述 Description 设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.如下图所示(见样 ...

随机推荐

  1. dubbo源码学习(四):暴露服务的过程

    dubbo采用的nio异步的通信,通信协议默认为 netty,当然也可以选择 mina,grizzy.在服务端(provider)在启动时主要是开启netty监听,在zookeeper上注册服务节点, ...

  2. linux常用命令 满足99%的开发需要

    1.# 表示权限用户(如:root),$ 表示普通用户开机提示:Login:输入用户名password:输入口令 用户是系统注册用户成功登陆后,可以进入相应的用户环境.退出当前shell,输入:exi ...

  3. 制作一个自己的xhprof测试平台

    1 1.首先安装php开发环境,比如lnmp. 2.安装xhprof ps: 记住从github上面下载(https://github.com/phacility/xhprof), 不要从pecl.p ...

  4. Linux/CentOS 7 timezone 修改

    1.su - 登录root用户 2.timedatectl set-timezone {timezone} (set后面加想要设置的时区) 举例:timedatectl set-timezone As ...

  5. 6358. 【NOIP2019模拟2019.9.15】小ω的仙人掌

    题目 题目大意 给你一串二元组\((a_i,b_i)\)的数列. 求最小的区间\([l,r]\)长度,满足\([l,r]\)中的每个二元组选或不选,使得\(\sum a_i=w\)且\(\sum b_ ...

  6. delphi xe10 手机内部系统相关操作(手机信息、震动、剪贴板、键盘、电话、拨号)

    //获取手机信息 function GetPhoneInfo(): string; Var TelephonyManager: JTelephonyManager; TelephonyServiceN ...

  7. thinkphp 数据缓存

    在ThinkPHP中进行缓存操作,一般情况下并不需要直接操作缓存类,因为系统内置对缓存操作进行了封装,直接采用S方法即可,例如: 缓存初始化 // 缓存初始化 S(array('type'=>' ...

  8. QueryList getData()方法中多次调用来实现递归多级采集。

    <?php require 'QueryList/vendor/autoload.php'; use QL\QueryList; //获取每个li里面的h3标签内容,和class为item的元素 ...

  9. 经典单调栈最大子矩形——牛客多校第二场H

    题目是求次大子矩形,那么在求最大子矩形的时候维护M1,M2即可 转移M2时比较的过程要注意一下 #include<bits/stdc++.h> using namespace std; # ...

  10. 创建用户的方法 3种mysql创建方法

    mysql创建用户的方法分成三种:INSERT USER表的方法.CREATE USER的方法.GRANT的方法.   一.账号名称的构成方式   账号的组成方式:用户名+主机(所以可以出现重复的用户 ...