版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36616023/article/details/82763122
题目描述
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}。实验Ej需要用到的仪器是I的子集RjÍI。配置仪器Ik的费用为ck美元。实验Ej的赞助商已同意为该实验结果支付pj美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
输入输出格式
输入格式:
第1行有2 个正整数m和n。m是实验数,n是仪器数。接下来的m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。
输出格式:
第1 行是实验编号;第2行是仪器编号;最后一行是净收益。
输入输出样例
输入样例#1: 复制
2 3
10 1 2
25 2 3
5 6 7
输出样例#1: 复制
1 2
1 2 3
17
说明
感谢@FlierKing 提供spj
n,m<=50
这道题数据是在windows生成的,输入数据中所有的换行都是’\r\n’而不是’\n’
题解:
还是最大权闭合子图,就是多了一下输出,经过的仪器应该是网络流中流过的那些点,可以dinic中的dis数组进行判断,也可以用sap算法把和T连边的点的权值改成0,再跑sap,如果最大流改变,说明这个点一定被用过,最多再跑50次sap算法
#include<bits/stdc++.h>
using namespace std;
const int maxn=50000;
struct node
{
int v,nxt;
int w;
}edge[maxn*4];
int s,t;
int viss[maxn];
int cnt=0,head[maxn];
const int inf=0x3f3f3f3f;
queue<int>q;
void add_edge(int u,int v,int w)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
int dis[maxn];
int bfs()
{
int x;
while(!q.empty())
q.pop();
memset(dis,0,sizeof(dis));
dis[s]=1;
q.push(s);
while(!q.empty())
{
x=q.front();
q.pop();
for(int i=head[x];i!=-1;i=edge[i].nxt)
{
if(edge[i].w&&!dis[edge[i].v])
{
dis[edge[i].v]=dis[x]+1;
if(edge[i].v==t)
return 1;
q.push(edge[i].v);
}
}
}
return 0;
}
int dfs(int x,int low)
{
if(x==t)
return low;
int temp=low;
int k;
for(int i=head[x];i!=-1;i=edge[i].nxt)
{
if(edge[i].w&&dis[edge[i].v]==dis[x]+1)
{
k=dfs(edge[i].v,min(temp,edge[i].w));
if(!k)
dis[edge[i].v]=0;
edge[i].w-=k;
edge[i^1].w+=k;
if(!(temp-=k))
break;
}
}
return low-temp;
}
int w[200];
int renwu[200];
vector<int>ve[210];
int jiqi[200];
int main ()
{
int m,n;
scanf("%d%d",&m,&n);
s=m+n+1;
t=s+1;
memset(head,-1,sizeof(head));
memset(viss,0,sizeof(viss));
cnt=0;
memset(w,0,sizeof(w));
for(int i=1;i<=m;i++)
ve[i].clear();
for(int i=1;i<=m;i++)
{
int flag=0;
int flagg=1;
while(flagg)
{
int xx;
scanf("%d",&xx);
char ch=getchar();
if(flag==0)
{
w[i]=xx;
add_edge(s,i,w[i]);
add_edge(i,s,0);
flag=1;
continue;
}
ve[i].push_back(xx+m);
add_edge(i,xx+m,inf);
add_edge(xx+m,i,0);
if(ch!=' ')
flagg=0;
}
}
int sum=0;
for(int i=1;i<=n;i++)
{
int xx;
scanf("%d",&xx);
add_edge(i+m,t,xx);
add_edge(t,i+m,0);
}
for(int i=1;i<=m;i++)
sum+=w[i];
int ans=0;
while(bfs())
{
ans+=dfs(s,inf);
}
int ji=0,ren=0;
for(int i=1;i<=n;i++)
{
if(dis[i+m]!=0)
{
viss[i+m]=1;
jiqi[++ji]=i;
}
}
for(int i=1;i<=m;i++)
{
int len=ve[i].size();
int flag=0;
for(int j=0;j<len;j++)
{
if(viss[ve[i][j]]==0)
{
flag=1;
break;
}
}
if(flag==0)
{
renwu[++ren]=i;
}
}
sort(renwu+1,renwu+1+ren);
sort(jiqi+1,jiqi+1+ji);
for(int i=1;i<=ren;i++)
{
if(i==1)
printf("%d",renwu[i]);
else
printf(" %d",renwu[i]);
}
printf("\n");
for(int i=1;i<=ji;i++)
{
if(i==1)
printf("%d",jiqi[i]);
else
printf(" %d",jiqi[i]);
}
printf("\n");
printf("%d\n",sum-ans);
}