uoj455 【UER #8】雪灾与外卖
题解:
https://blog.csdn.net/litble/article/details/88410435
https://www.mina.moe/archives/11762
以下是我瞎bb的:
如果我没看错的话,这个模拟费用流模拟的根本不是一般的最短增广路算法,模拟的是消圈算法...无语,为什么网上好像都直接当成对的了。另外,如果真的从费用流模型开始思考的话,好像会累死人而且完全没有结果;还是应该当做一个贪心来看待,费用流当做证明方法就行了
消圈算法就是先随便跑一个最大流,然后每次找出任意一个"残量网络(指只保留'原图中边和用于退流的反向边中剩余可用容量不为0的边'形成的图)中的负费用环",增广满,直到找不到负费用环,此时就是最小费用最大流(证明咕咕咕了)
这题里面如果遇到传送点时箱子堆是空的,就直接丢进传送点堆就行(代价自然为费用-位置);如果遇到箱子时传送点堆是空的,要假设左侧无限远处有无限个传送点(由于传送点不一定必须被匹配,但是箱子一定必须被匹配);同样的,遇到传送点时如果进行匹配不能让答案更小,就不要匹配,直接丢进传送点堆
这题餐厅可能可以多次匹配,方法是记一个pair,第二维是剩余容量,要拆的时候拆;直接这样搞复杂度是错的,但是向餐厅堆里面插入元素的次数是可以控制的(把多次一样的插入并成插入一次一个pair),这样复杂度就对了;复杂度证明网上有
最终代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
struct P
{
ll x,y;
};
bool operator<(const P &a,const P &b)
{
return a.x>b.x;
}
struct PP
{
int x,w,c;
}p[];
bool operator<(const PP &a,const PP &b)
{
return a.x<b.x;
}
int n,m;
ll ans;
priority_queue<P> q1,q2;
int main()
{
int i;P t;ll v,ts=,t1,t2;
scanf("%d%d",&n,&m);
for(i=;i<=n;++i)
{
scanf("%d",&p[i].x);
p[i].c=-;
}
for(i=;i<=m;++i)
{
scanf("%d%d%d",&p[i+n].x,&p[i+n].w,&p[i+n].c);
ts+=p[i+n].c;
}
if(n>ts) {puts("-1");return ;}
sort(p+,p+n+m+);
for(i=;i<=n+m;++i)
{
if(p[i].c==-)
{
if(q2.empty()) v=1e11;
else
{
t=q2.top();q2.pop();
v=t.x;
if(t.y!=) q2.push((P){t.x,t.y-});
}
ans+=p[i].x+v;
q1.push((P){-*p[i].x-v,});
}
else
{
t1=;
while(p[i].c && !q1.empty())
{
t=q1.top();v=t.x;
if(p[i].x+p[i].w+v>=) break;
q1.pop();
t2=min(ll(p[i].c),t.y);
t.y-=t2;p[i].c-=t2;
ans+=t2*(p[i].x+p[i].w+v);
t1+=t2;
q2.push((P){-*p[i].x-v,t2});
if(t.y) q1.push(t);
}
if(t1) q1.push((P){-p[i].x-p[i].w,t1});
if(p[i].c) q2.push((P){p[i].w-p[i].x,p[i].c});
}
}
printf("%lld\n",ans);
return ;
}
暴力( 最暴力的费用流,$O(n^2)$条边):
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
#define fi first
#define se second
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
struct pli
{
ll fi;int se;
};
bool operator>(const pli &a,const pli &b)
{
return a.fi>b.fi || (a.fi==b.fi && a.se>b.se);
}
const ll inf=0x3f3f3f3f3f3f3f3f;
namespace F
{ struct E
{
int to,nxt,from;
ll d,cap,flow;
}e[];
int f1[],ne=;
int S,T,n;
bool inq[],*vis=inq;
ll d[];
ll h[];
ll flow,cost;
typedef __gnu_pbds::priority_queue<pli,greater<pli> > pq;
pq::point_iterator it[];
//const int INF=0x3f3f3f3f;
bool spfa()
{
int u,k,k1;
memset(d,0x3f,sizeof(d[])*(n+));
memset(inq,,sizeof(inq[])*(n+));
queue<int> q;
q.push(T);d[T]=;inq[T]=;
while(!q.empty())
{
u=q.front();q.pop();
inq[u]=;
for(k1=f1[u];k1;k1=e[k1].nxt)
{
k=k1^;
if(e[k].cap>e[k].flow&&d[u]+e[k].d<d[e[k].from])
{
d[e[k].from]=d[u]+e[k].d;
if(!inq[e[k].from])
{
inq[e[k].from]=;
q.push(e[k].from);
}
}
}
}
return d[S]!=inf;
}
bool dij()
{
int i,u,k,k1;pli t;
memset(d,0x3f,sizeof(d[])*(n+));
memset(vis,,sizeof(vis[])*(n+));
pq q;
for(i=;i<=n;i++) it[i]=q.end();
it[T]=q.push((pli){,T});d[T]=;
while(!q.empty())
{
t=q.top();q.pop();
u=t.se;
if(vis[u]) continue;
vis[u]=;
for(k1=f1[u];k1;k1=e[k1].nxt)
{
k=k1^;
if(e[k].cap>e[k].flow&&d[u]+e[k].d+h[u]-h[e[k].from]<d[e[k].from])
{
d[e[k].from]=d[u]+e[k].d+h[u]-h[e[k].from];
if(it[e[k].from]!=q.end()) q.modify(it[e[k].from],(pli){d[e[k].from],e[k].from});
else it[e[k].from]=q.push((pli){d[e[k].from],e[k].from});
}
}
}
return d[S]!=inf;
}
void update()
{
for(int i=;i<=n;i++) h[i]+=d[i];
}
ll dfs(int u,ll x)
{
if(u==T||x==) return x;
ll flow=,f;
vis[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].cap>e[k].flow&&h[e[k].to]==h[u]-e[k].d)
{
f=dfs(e[k].to,min(x-flow,e[k].cap-e[k].flow));
e[k].flow+=f;e[k^].flow-=f;flow+=f;
if(flow==x) return flow;
}
return flow;
}
void augment()
{
ll f;
while()
{
memset(vis,,sizeof(vis[])*(n+));
f=dfs(S,inf);
if(!f) break;
flow+=f;cost+=f*h[S];
}
}
void solve()
{
flow=cost=;
memset(h,,sizeof(h[])*(n+));
if(!spfa()) return;
do
{
update();
augment();
}while(dij());
}
void me(int a,int b,ll c,ll d)
{
e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;e[ne].from=a;
e[ne].cap=c;e[ne].d=d;
e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;e[ne].from=b;
e[ne].cap=;e[ne].d=-d;
} } ll abs1(ll a){return a>=?a:-a;}
int n,m;
int x[],y[],w[],c[];
int main()
{
int i,j;ll ts=;
scanf("%d%d",&n,&m);
for(i=;i<=n;++i)
scanf("%d",x+i);
for(i=;i<=m;++i)
{
scanf("%d%d%d",y+i,w+i,c+i);
ts+=c[i];
}
if(n>ts) {puts("-1");return ;}
F::S=n+m+;F::T=n+m+;F::n=n+m+;
for(i=;i<=n;++i)
F::me(F::S,i,,);
for(i=;i<=n;++i)
for(j=;j<=m;++j)
F::me(i,j+n,inf,abs1(x[i]-y[j]));
for(i=;i<=m;++i)
F::me(i+n,F::T,c[i],w[i]);
F::solve();
printf("%lld\n",F::cost);
return ;
}
暴力(优化到O(n)条边):
%:pragma GCC optimize("Ofast")
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
#define fi first
#define se second
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
struct pli
{
ll fi;int se;
};
bool operator>(const pli &a,const pli &b)
{
return a.fi>b.fi || (a.fi==b.fi && a.se>b.se);
}
const ll inf=0x3f3f3f3f3f3f3f3f;
namespace F
{ struct E
{
int to,nxt,from;
ll d,cap,flow;
}e[];
int f1[],ne=;
int S,T,n;
bool inq[],*vis=inq;
ll d[];
ll h[];
ll flow,cost;
typedef __gnu_pbds::priority_queue<pli,greater<pli> > pq;
pq::point_iterator it[];
//const int INF=0x3f3f3f3f;
bool spfa()
{
int u,k,k1;
memset(d,0x3f,sizeof(d[])*(n+));
memset(inq,,sizeof(inq[])*(n+));
queue<int> q;
q.push(T);d[T]=;inq[T]=;
while(!q.empty())
{
u=q.front();q.pop();
inq[u]=;
for(k1=f1[u];k1;k1=e[k1].nxt)
{
k=k1^;
if(e[k].cap>e[k].flow&&d[u]+e[k].d<d[e[k].from])
{
d[e[k].from]=d[u]+e[k].d;
if(!inq[e[k].from])
{
inq[e[k].from]=;
q.push(e[k].from);
}
}
}
}
return d[S]!=inf;
}
bool dij()
{
int i,u,k,k1;pli t;
memset(d,0x3f,sizeof(d[])*(n+));
memset(vis,,sizeof(vis[])*(n+));
pq q;
for(i=;i<=n;i++) it[i]=q.end();
it[T]=q.push((pli){,T});d[T]=;
while(!q.empty())
{
t=q.top();q.pop();
u=t.se;
if(vis[u]) continue;
vis[u]=;
for(k1=f1[u];k1;k1=e[k1].nxt)
{
k=k1^;
if(e[k].cap>e[k].flow&&d[u]+e[k].d+h[u]-h[e[k].from]<d[e[k].from])
{
d[e[k].from]=d[u]+e[k].d+h[u]-h[e[k].from];
if(it[e[k].from]!=q.end()) q.modify(it[e[k].from],(pli){d[e[k].from],e[k].from});
else it[e[k].from]=q.push((pli){d[e[k].from],e[k].from});
}
}
}
return d[S]!=inf;
}
void update()
{
for(int i=;i<=n;i++) h[i]+=d[i];
}
ll dfs(int u,ll x)
{
if(u==T||x==) return x;
ll flow=,f;
vis[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].cap>e[k].flow&&h[e[k].to]==h[u]-e[k].d)
{
f=dfs(e[k].to,min(x-flow,e[k].cap-e[k].flow));
e[k].flow+=f;e[k^].flow-=f;flow+=f;
if(flow==x) return flow;
}
return flow;
}
void augment()
{
ll f;
while()
{
memset(vis,,sizeof(vis[])*(n+));
f=dfs(S,inf);
if(!f) break;
flow+=f;cost+=f*h[S];
}
}
void solve()
{
flow=cost=;
memset(h,,sizeof(h[])*(n+));
if(!spfa()) return;
do
{
update();
augment();
}while(dij());
}
void me(int a,int b,ll c,ll d)
{
e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;e[ne].from=a;
e[ne].cap=c;e[ne].d=d;
e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;e[ne].from=b;
e[ne].cap=;e[ne].d=-d;
//printf("1t%d %d %lld %lld\n",a,b,c,d);
} } ll abs1(ll a){return a>=?a:-a;}
int n,m;
int x[],y[],w[],c[];
int main()
{
int i,j;ll ts=;
scanf("%d%d",&n,&m);
for(i=;i<=n;++i)
scanf("%d",x+i);
for(i=;i<=m;++i)
{
scanf("%d%d%d",y+i,w+i,c+i);
ts+=c[i];
}
if(n>ts) {puts("-1");return ;}
F::S=n+*m+;F::T=n+*m+;F::n=n+*m+;
for(i=;i<m;++i)
F::me(i,i+,inf,y[i+]-y[i]);
for(i=m;i>;--i)
F::me(i+m,i-+m,inf,y[i]-y[i-]);
for(i=;i<=m;++i)
{
F::me(i,i+*m,inf,);
F::me(i+m,i+*m,inf,);
F::me(i+*m,F::T,c[i],w[i]);
}
for(i=,j=;i<=n;++i)
{
while(j<=m && y[j]<x[i]) ++j;
if(j!=) F::me(i+*m,j-+m,,x[i]-y[j-]);
if(j!=m+) F::me(i+*m,j,,y[j]-x[i]);
F::me(F::S,i+*m,,);
}
F::solve();
printf("%lld\n",F::cost);
return ;
}
数据生成器
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<chrono>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
ull splitmix64(ull x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> )) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> )) * 0x94d049bb133111eb;
return x ^ (x >> );
}
ull rd()
{
static ull x=splitmix64(chrono::steady_clock::now().time_since_epoch().count());
return splitmix64(x=x*6364136223846793005ull+1442695040888963407ull);
}
ll randint(ll l,ll r)
{
return rd()%(r-l+)+l;
}
int n=randint(,),m=randint(,);
struct P
{
int y,w,c;
}t2[];
bool operator<(const P &a,const P &b)
{
return a.y<b.y;
}
int t1[];
int main()
{
int i;
for(i=;i<=n;++i)
t1[i]=randint(,1e9);
for(i=;i<=m;++i)
t2[i].y=randint(,1e9),t2[i].w=randint(,1e9),t2[i].c=randint(,1e9);
sort(t1+,t1+n+);
sort(t2+,t2+m+);
printf("%d %d\n",n,m);
for(i=;i<=n;++i)
printf("%d ",t1[i]);
puts("");
for(i=;i<=m;++i)
printf("%d %d %d\n",t2[i].y,t2[i].w,t2[i].c);
return ;
}
对拍脚本
#!/bin/bash
set -v on
while [ = ]
do
./1_2.out >t1.txt
echo "running 1"
./.out <t1.txt >t2.txt
echo "running 2"
./1_1.out <t1.txt >t3.txt
diff -w t2.txt t3.txt
if [ $? != ]
then read -n
fi
cat t2.txt
done
优化暴力和最终代码拍了一下,应该是没问题了
一堆草稿...
令
uoj455 【UER #8】雪灾与外卖的更多相关文章
- [UOJ455][UER #8]雪灾与外卖——堆+模拟费用流
题目链接: [UOJ455]雪灾与外卖 题目描述:有$n$个送餐员(坐标为$x_{i}$)及$m$个餐厅(坐标为$y_{i}$,权值为$w_{i}$),每个送餐员需要前往一个餐厅,每个餐厅只能容纳$c ...
- UOJ #455 [UER #8]雪灾与外卖 (贪心、模拟费用流)
题目链接 http://uoj.ac/contest/47/problem/455 题解 模拟费用流,一个非常神奇的东西. 本题即为WC2019 laofu的讲课中的Problem 8,经典的老鼠进洞 ...
- 【UER #8】雪灾与外卖
题解: 这个东西的模型是个费用流 但是直接跑费用流能拿到5分的高分 $(nm)*(nm)*log{nm}$ 考虑优化一下建图 我们可以不用对每个店和人都连边 而是对人和店都连一条链 然后对每个人连店刚 ...
- 题解-UOJ 455雪灾与外卖
Problem \(\mathrm{UOJ~455}\) 题意概要:一根数轴上有 \(n\) 只老鼠与 \(m\) 个洞,每个洞有费用与容量限制,要求每只老鼠要进一个洞且每个洞的老鼠不超过自身的容量限 ...
- NOIWC2019 冬眠记
冬眠 由于THUWC考太差了没啥心情做事…… Day -1 报到日前一天晚上去看了看宿舍表,发现周围全是集训队,隔壁就是栋爷.高队和lca,再隔壁是zzq和wxh……吓傻了(本校buff这么好吗) D ...
- [codevs 2800]送外卖
题目描述 Description 有一个送外卖的,他手上有n份订单,他要把n份东西,分别送达n个不同的客户的手上.n个不同的客户分别在1~n个编号的城市中.送外卖的从0号城市出发,然后n个城市都要走一 ...
- codevs2800 送外卖
题目描述 Description 有一个送外卖的,他手上有n份订单,他要把n份东西,分别送达n个不同的客户的手上.n个不同的客户分别在1~n个编号的城市中.送外卖的从0号城市出发,然后n个城市都要走一 ...
- 项目vue2.0仿外卖APP(一)
最近用vue.js做一个仿饿了么外卖APP的项目,现在也把流程啊什么的暂时先整理一下在这个博客上面. 当然,这个过程会有点长,不过确实能学到很多东西. 话不多说,马上开始吧. 1.项目介绍 选用当前最 ...
- 【CodeVS2800】 送外卖 最短路+状压DP
首先求出各点之间的最短路,floyed即可,注意是0-n. 然后考虑状压,f[i][j]表示状态为i时访问j点时的最短路和,1表示访问,0表示未访问,然后第j个点所在的位置就是(1<<j) ...
随机推荐
- xdebug浏览器调试参数
XDEBUG_SESSION_START=phpstorm-xdebug 找到对应PHP版本的 Xdebug ,后面带 TS 的为线程安全,本机环境为 win7 64 + php-5.5.1-Win3 ...
- python中全局变量的使用
python中在module定义的变量可以认为是全局变量, 而对于全局变量的赋值有个地方需要注意. test.py ------------------------------------------ ...
- MySQL查询计划输出列的含义
"一:MySQL查询计划输出列的含义:1.id:每个被独立执行的操作的标识,表示对象被操作的顺序:id值越大,先被执行:如果相同,执行顺序从上到下.2.select_type:查询中每个se ...
- 数组排序----Demo
//选择排序,分为简单选择排序.树形选择排序(锦标赛排序).堆排序 此算法为简单选择排序 public static void selectSort(int[] a){ for(int i=0;i&l ...
- java try catch 与 throws 使用场景以及怎么合理使用?
对于如下场景,给出不同的看法: 其实我更多的疑问在于,自定义的方法里面java api抛出了异常,这个时候,我是需要捕获呢?还是我也继续往上抛. 比如,我这里定义了一个日期处理的方法,有两种对异常的处 ...
- shell入门-tr替换字符和split切割大文件
命令:tr 说明:替换字符 格式tr ‘原字符’ ‘新字符’ 可以是范围字符,指定字符 命令:split 选项:-b 50m 1.txt 根据大小分割 单位是b不用单位,单位是兆加m -l 100 ...
- wdcp安全设置,让你的后台,只有你自己能访问
wdcp安全设置,让你的后台,只有你自己能访问 wdcp的后台,默认端口,是8080,可以修改为其它端口wdcp的后台,可以限制IP地址的访问,也可以限制域名的访问做了这些限制与设置后,已相对安全了, ...
- Flask14 渲染问题、API、项目文档
3 前端渲染和后端渲染 这两种渲染都属于动态页面 区分前后端渲染的关键点是站在浏览器的角度 3.1 后端渲染 浏览器请求服务器后获取到的是完整的HTML页面(即:后台已经组装好HTML文件啦),利用f ...
- R语言中的字符处理
R语言中的字符处理 (2011-07-10 22:29:48) 转载▼ 标签: r语言 字符处理 字符串 连接 分割 分类: R R的字符串处理能力还是很强大的,具体有base包的几个函数和strin ...
- java多态和强制类型转换
子类可以赋值给超类,称之为向上转型,这个是自动的. 超类不可以赋值给子类,这个是向下转型,需要我们手动实现. 赋值给超类的子类引用在运行期间将表现出不同的特性,这就是多态. 小类型 可转换为 ...