P3705 [SDOI2017]新生舞会 01规划+费用流
P3705 [SDOI2017]新生舞会
思路:
这个方程式一看就是01规划。我们考虑二分之后,怎么搞。
因为所以人都要匹配,跑费用就可以了。
#include<bits/stdc++.h>
#define re register
#define LL long long
using namespace std;
const LL maxn = 200 + 10;
const LL maxm=1e6+10;
const LL inf=1<<30;
const LL INF = 0x3f3f3f3f3f3f3f3f;
struct po {
LL to;
double dis;
LL nxt, w;
} edge[maxm<<1];
struct max_folw {
double dis[maxn];
LL vis[maxn];
LL head[maxn];
LL n,s,t,cut=-1;
LL ans=0;
double fy=0;
void init(LL N, LL S, LL T) {
ans=0, fy=0;
cut=-1;
n=N, s=S, t=T;
memset(head, -1, sizeof(head));
}
void add_edge(LL from,LL to,LL w,double dis) {
edge[++cut].nxt=head[from];
edge[cut].to=to;
edge[cut].w=w;
edge[cut].dis=dis;
head[from]=cut;
}
void add(LL from,LL to,LL w,double dis) {
add_edge(from,to,w,dis);
add_edge(to,from,0,-dis);
}
bool spfa() {
memset(vis,0,sizeof(vis));
for(re LL i=0; i<=n; i++)
dis[i]=inf;
dis[t]=0;
vis[t]=1;
deque<LL> q;
q.push_back(t);
while(!q.empty()) {
LL u=q.front();
vis[u]=0;
q.pop_front();
for(re LL i=head[u]; i!=-1; i=edge[i].nxt) {
LL v=edge[i].to;
if(edge[i^1].w>0&&dis[v]>dis[u]-edge[i].dis) {
dis[v]=dis[u]-edge[i].dis;
if(!vis[v]) {
vis[v]=1;
if(!q.empty()&&dis[v]<dis[q.front()])
q.push_front(v);
else
q.push_back(v);
}
}
}
}
return dis[s]<inf;
}
LL dfs(LL u,LL low) {
if(u==t) {
vis[t]=1;
return low;
}
LL diss=0;
vis[u]=1;
for(re LL i=head[u]; i!=-1; i=edge[i].nxt) {
LL v=edge[i].to;
if(!vis[v]&&edge[i].w!=0&&dis[u]-edge[i].dis==dis[v]) {
LL check=dfs(v,min(edge[i].w,low));
if(check>0) {
fy+=check*edge[i].dis;
edge[i].w-=check;
edge[i^1].w+=check;
low-=check;
diss+=check;
if(low==0)
break;
}
}
}
return diss;
}
void max_flow() {
while(spfa()) { //流量+k
vis[t]=1;
while(vis[t]) {
memset(vis,0,sizeof(vis));
ans+=dfs(s,inf);
}
}
}
} flow;
LL a[105][105], b[105][105];
int n;
int ok(double r){
flow.init(2*n+5, 0, 2*n+1);
for(int i=1; i<=n; i++){
flow.add(0, i, 1, 0);
flow.add(i+n, 2*n+1, 1, 0);
for(int j=1; j<=n; j++){
flow.add(i, n+j, 1, r*b[i][j]-a[i][j]);
}
}
flow.max_flow();
return flow.fy>=0;
}
int main(){
scanf("%d", &n);
for(LL i=1; i<=n; i++){
for(LL j=1; j<=n; j++){
scanf("%lld", &a[i][j]);
}
}
for(LL i=1; i<=n; i++){
for(LL j=1; j<=n; j++){
scanf("%lld", &b[i][j]);
}
}
double L=0, R=1<<30, mid;
int siz=60;
while(siz--){
mid=(L+R)/2;
if(ok(mid)){//<0
R=mid;
}
else{
L=mid;
}
}
printf("%.6f\n", mid);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)