SPCLN: 太空清扫 题目描述
一架宇宙飞船准备要穿过一条长长的星际隧道。隧道由 N 个静止的太空碎片组成。为了成功 地完成任务,飞船需要摧毁所有太空碎片。飞船的控制单元由 M 个按钮组成,这些按钮可以被用 来摧毁太空碎片。按下某个特定的按钮可能造成某些(也许多个)太空碎片被摧毁。一旦一个太 空碎片被摧毁,其质量将被转换成能量,这些能量将最终被飞船所吸收以提高其速度。一个特定 碎片被摧毁所释放的能量与被用来摧毁它的按钮有关。我们定义一个能量矩阵 E,对于每个碎片 i 和按钮 j,E[i][j](0 ≤ E[i][j] ≤ 100) 表示用按钮 j 摧毁碎片 i 所释放的能量。若 E[i][j] = −1 表 示碎片 i 不能被按钮 j 摧毁。
一些碎片的摧毁有依赖关系。飞船必须在摧毁某些碎片前先将另一些碎片摧毁。这里一共有 K 组依赖关系。每组依赖关系包含两个用空格隔开的整数 i 和 j,表示碎片 i 的摧毁必须发生在碎 片 j 的摧毁之前。
每一个按钮只能被按下一次,而且必须按照 1 ∼ M 的顺序按下(如按钮 2 不能在按钮 1 前被 按下)。当按下一个按钮时,我们定义“目标向量”为一个长为 N 的二进制字符串 T 。对于碎片 i,若 T [i] 为 1,表示你希望用这个按钮去摧毁碎片 i,否则 T [i] 为 0。当按钮被按下时,所有在目 标向量中出现过的碎片将同时被摧毁。
飞船可以用某个按钮摧毁任意数量的碎片,包括 0 个,只要它们能被这个按钮摧毁,并满足 依赖关系。
现在你的任务是计算飞船通过这条隧道所能获得的最大平均能量。
输入格式
输入第一行包括两个用空格隔开的整数 N 和 M。
接下来 N 行,每行 M 个整数,表示 E[i][j]。
接下来一行包含一个整数 K。
接下来 K 行,每行包含两个用空格隔开的整数 u 和 v(u ̸= v),表示碎片 u 必须在碎片 v 前
被摧毁。
输出格式
输出一个实数表示最大平均能量,请四舍五入保留小数点后两位。
数据范围与约定
• 1 ≤ M, N ≤ 100
• 0≤K≤100
• −1≤E[i][j]≤100
• 1≤u,v≤N
• 数据保证存在摧毁所有碎片的方案。
样例数据
输入
3 3
10 70 100
80 50 40
80 20 40
2
1 2
1 3
输出
50.00
样例解释
唯一的摧毁所有碎片的方案为:用第二个按钮摧毁第一个碎片,用第三个按钮摧毁第二个和 第三个碎片。
平均能量为 (70 + 40 + 40)/3 = 50.00。
题解:这题问了qls才知道怎么做的。
因为题目说了要摧毁所有的碎片,所以就是最大化能量总和。
这样建图:对于每个碎片拆成m+1个点,第i个碎片的第j个点向第j+1个点连一条100-E[i][j]的边,对于k个限制条件,如果碎片u要在碎片v之前被摧毁,那么碎片u的第j个点向第j+1个点连容量为inf的边,然后源点s向每个碎片的第一个点连一条容量为inf的边,每个碎片的最后一点向汇端t连一条容量为inf的边,然后跑一遍s-t的最小割,记最小割为ans,用(100*n-ans)/n即为答案
神建图!
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<queue> #include<stack> using namespace std; #define rep(i,a,n) for (int i=a;i<n;i++) #define per(i,a,n) for (int i=n-1;i>=a;i--) #define pb push_back #define fi first #define se second typedef vector<int> VI; typedef long long ll; typedef pair<int,int> PII; const int inf=0x3fffffff; const ll mod=1000000007; const int maxn=11000; const int maxm=100500; struct Node { int from,to,next; int cap; }edge[maxm]; int tol; int dep[maxn]; int head[maxn]; void init() { tol=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w)//第一条边下标必须为偶数 { edge[tol].from=u;edge[tol].to=v;edge[tol].cap=w;edge[tol].next=head[u];head[u]=tol++; edge[tol].from=v;edge[tol].to=u;edge[tol].cap=0;edge[tol].next=head[v];head[v]=tol++; } int BFS(int start,int end) { int que[maxn]; int front,rear; front=rear=0; memset(dep,-1,sizeof(dep)); que[rear++]=start; dep[start]=0; while(front!=rear) { int u=que[front++]; if(front==maxn)front=0; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(edge[i].cap>0&&dep[v]==-1) { dep[v]=dep[u]+1; que[rear++]=v; if(rear>=maxn)rear=0; if(v==end)return 1; } } } return 0; } int a[110][110]; int dinic(int start,int end) { int res=0; int top; int stack[maxn]; int cur[maxn]; while(BFS(start,end)) { memcpy(cur,head,sizeof(head)); int u=start; top=0; while(1) { if(u==end) { int min=inf; int loc; for(int i=0;i<top;i++) if(min>edge[stack[i]].cap) { min=edge[stack[i]].cap; loc=i; } for(int i=0;i<top;i++) { edge[stack[i]].cap-=min; edge[stack[i]^1].cap+=min; } res+=min; top=loc; u=edge[stack[top]].from; } for(int i=cur[u];i!=-1;cur[u]=i=edge[i].next) if(edge[i].cap!=0&&dep[u]+1==dep[edge[i].to]) break; if(cur[u]!=-1) { stack[top++]=cur[u]; u=edge[cur[u]].to; } else { if(top==0)break; dep[u]=-1; u=edge[stack[--top]].from; } } } return res; } int main() { int n,m,k; scanf("%d%d",&n,&m); init(); int st=0,ed=n*(m+1)+1; rep(i,1,n+1) rep(j,1,m+1) scanf("%d",&a[i][j]); rep(i,1,n+1) rep(j,1,m+1) addedge((m+1)*(i-1)+j,(m+1)*(i-1)+j+1,100-a[i][j]); rep(i,1,n+1) addedge(st,(i-1)*(m+1)+1,inf),addedge(i*(m+1),ed,inf); scanf("%d",&k); rep(i,1,k+1) { int u,v; scanf("%d%d",&u,&v); rep(j,1,m+1) addedge((u-1)*(m+1)+j,(v-1)*(m+1)+j+1,inf); } printf("%.2lf ",1.0*(100*n-dinic(st,ed))/n); return 0; }