做过的大概是最难的01规划了吧。
这个是精髓。
然后就是一个又有边权又有点权的最大权闭合图问题。
BZOJ2127,BZOJ2039。
这两个做了就会了。
把一个边拆成新点点权为边权。
连有向边向u,v。
原理来自定义。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
const int INF=1e9+10;
const int N=40000;
inline void read(int &x){
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
int n,S,T;
int p[101][101]={0};
int edge[101][101]={0};
struct Front_star{
int u,v,nxt;
double w;
}e[N*4];
int cnt=1;
int tot=0;
int first[N]={0};
void addedge(int u,int v,double w){
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].nxt=first[u];
first[u]=cnt;
}
void add(int u,int v,double w){
addedge(u,v,w);
addedge(v,u,0);
}
double pos=0;
void build_gra(double sum){
cnt=1;
memset(first,0,sizeof(first));
pos=0;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
add(edge[i][j],i,INF);
add(edge[i][j],j,INF);
if(p[i][j]+2*sum<0){
add(edge[i][j],T,-(p[i][j]+2*sum));
}
else{
pos+=(p[i][j]+2*sum);
add(S,edge[i][j],(p[i][j]+2*sum));
}
}
}
for(int i=1;i<=n;i++){
if(-199.0*sum>0){
pos+=-(199.0*sum);
add(S,i,-(199.0*sum));
}
else{
add(i,T,199.0*sum);
}
}
}
int d[N]={0};
queue<int> q;
bool SPFA(){
for(int i=S;i<=T;i++){
d[i]=-1;
}
q.push(S);
d[S]=1;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=first[x];i;i=e[i].nxt){
int v=e[i].v;
if(e[i].w&&d[v]==-1){
d[v]=d[x]+1;
q.push(v);
}
}
}
return d[T]!=-1;
}
double dfs(int st,int ed,double nowdat){
if(st==ed){
return nowdat;
}
double dat=0;
for(int i=first[st];i;i=e[i].nxt){
int v=e[i].v;
if(e[i].w&&d[v]==d[st]+1){
double now=min(e[i].w,nowdat-dat);
now=dfs(v,ed,now);
dat+=now;
e[i].w-=now;
e[i^1].w+=now;
if(dat==nowdat){
return dat;
}
}
}
if(!dat){
d[st]=-2;
}
return dat;
}
double check(){
double s=0;
while(SPFA()){
s+=dfs(S,T,INF);
}
// cout<<pos<<" "<<s<<endl;
return pos-s;
}
int main(){
read(n);
tot=n+1;
for(int i=1;i<=n;i++){
char ch[130];
scanf("%s",ch);
for(int j=0;j<n;j++){
p[i][j+1]=ch[j]-'0';
edge[i][j+1]=++tot;
}
}
/*for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<p[i][j]<<endl;
}
}*/
// cout<<tot<<endl;s
S=0;
T=++tot;
// cout<<tot<<endl;
// build_gra(0.2);
// cout<<(double)check();
double l=0;
double r=200000+20;
double eps=0.0000000001;
while(r-l>eps){
double mid=(l+r)/2;
build_gra(mid);
// cout<<l<<" "<<r<<" "<<mid<<endl;
if(check()>(double)0){
l=mid;
}
else{
r=mid;
}
// cout<<l<<" "<<r<<endl;
}
printf("%.7lf",l);
}

本文深入探讨了最大权闭合图问题的解决方法,通过将边权转化为点权并构建特殊图结构来实现。文章详细介绍了算法的实现过程,并提供了一个具体的编程示例,包括如何使用SPFA算法进行最短路径搜索以及基于此的增广路查找。
1063

被折叠的 条评论
为什么被折叠?



