貌似叫最大权闭合子图?(反正这些高端大气上档次的名词我都不知道)
建模比较有趣
先想最大流 大概是源连实验 实验连仪器 仪器连汇 然后发现无论怎么分配都做不到捆绑并只计算一次费用 弃疗
最小费用最大流 怎么建都是所有点都选才是最大流 更不靠谱 弃疗
最小割(不要问我为什么没想上下界 因为我还没学会)
我们发现按照上述最大流的建图方法 然后实验和仪器之间流量为inf 这样的话就可以保证一个实验和他需要的仪器捆绑
实验和源点之间是贡献 仪器和汇点之间是费用 这样的话就构成了这个模型
贡献可以这么考虑 本来我们选择的是所有的总贡献 所以割掉一条边其实是减去了贡献 费用更好理解了 割掉了就是花掉了嘛
所以我们根据最大流=最小割跑一遍最大流
然后看跟源点相连的实验和仪器就是要选的 所以这个问题就解决啦
这个题读入真的毒瘤(大雾)
附代码。
#include
#include
#include
#include
#include
#include
#include
#define inf 20021225
#define ll long long
using namespace std;
queue que;
int dis[110],cnt=1,in[110],s,t;
struct edge{int to,lt,f;}e[60000];
void add(int x,int y,int f)
{
e[++cnt].to=y;e[cnt].lt=in[x];e[cnt].f=f;in[x]=cnt;
e[++cnt].to=x;e[cnt].lt=in[y];e[cnt].f=0;in[y]=cnt;
}
bool bfs(int f)
{
while(!que.empty()) que.pop();
memset(dis,0,sizeof(dis));
que.push(s);dis[s]=1;
while(!que.empty())
{
int x=que.front();que.pop();//printf("%d",x);
for(int i=in[x];i;i=e[i].lt)
{
int y=e[i].to;
//printf("%d %d\n",y,e[i].f);
if(!dis[y]&&e[i].f)
{
dis[y]=dis[x]+1;//printf("%d\n",y);
if(y==t&&f) return 1;
que.push(y);
}
}
}
return 0;
}
int dfs(int x,int flow)
{
if(x==t||!flow) return flow;
int cur=flow;
for(int i=in[x];i;i=e[i].lt)
{
int y=e[i].to;
if(dis[y]==dis[x]+1&&e[i].f)
{
int tmp=dfs(y,min(cur,e[i].f));
e[i].f-=tmp;e[i^1].f+=tmp;cur-=tmp;
if(!cur) return flow;
}
}
dis[x]=-1;
return flow-cur;
}
bool vis[110];
int dinic()
{
int ans=0;
while(bfs(1)) ans+=dfs(s,inf);
bfs(0);return ans;
}
char tools[10000];
int c[110],ee[110];
vector v[110];
int main()
{
int n,m,i,tot=0;
scanf("%d%d",&m,&n);
s=m+n+1;t=s+1;
for(i=1;i<=m;i++)
{
scanf("%d",&c[i]);
add(s,i,c[i]);
memset(tools,0,sizeof tools);
cin.getline(tools,10000);
int ulen=0,tool;
while (sscanf(tools+ulen,"%d",&tool)==1)
{
add(i,tool+m,inf);v[i].push_back(tool);
//printf("%d\n",tool);
if (tool==0)
ulen++;
else {
while (tool) {
tool/=10;
ulen++;
}
}
ulen++;
}
}
for(i=1;i<=n;i++) scanf("%d",&ee[i]),add(i+m,t,ee[i]);
dinic();
for(i=1;i<=m;i++)
if(dis[i])
printf("%d ",i),tot+=c[i];
printf("\n");
for(i=1;i<=n;i++)
if(dis[i+m]) printf("%d ",i),tot-=ee[i];
printf("\n%d\n",tot);
return 0;
}