求最大值用最短路求解,求最小值用最长路求解,当然我们可以把图中所有的边权取负,求取最短路,两者是等价的。
求最小值
Intervals
题意:给定n个区间,[ai,bi]这个区间至少选选出ci个整数,求一个集合z,满足每个区间的要求,输出集合z的大小。
思路,用dis[i],表示从0到i最少需要多少个整数,则dis[b]-dis[a-1]>=c;dis[i]-dis[i-1]>=0;dis[i]-dis[i-1]<=1,dis[i]一定比dis[i-1]大,且最多大1,因为每个数只能选一次由于是从0开始,数组不能存负1,所以我们全部加一,用dis[i+1]表示0到i,其中,题目中还有隐含条件,0<=dis[i]-dis[i-1]<=1.约束条件找好了
统一一下方向,
dis[b+1]-dis[a]>=0;
dis[i]-dis[i-1]>=0;
dis[i-1]-dis[i]>=-1;
由于我的for是1到mx,所以这样写,你也可以让i+1和i比 那样for循环就从0到mx-1
代码
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<iostream>
#include<string>
#include<vector>
#define N 50000
#define inf 0x3f3f3f
using namespace std;
int net[N*4],fir[N*4],to[N*4],w[N*4];
int cnt,dis[N],vis[N];
void add(int x,int y,int z)
{
net[cnt]=fir[x];
fir[x]=cnt;
to[cnt]=y;
w[cnt]=z;
cnt++;
}
void spfa(int n)
{
memset(dis,0xc0,sizeof(dis));
dis[0]=0;
queue<int>q;
q.push(0);
vis[0]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=fir[u]; i; i=net[i])
{
int v=to[i];
int ww=w[i];
if(dis[v]<dis[u]+ww)
{
dis[v]=dis[u]+ww;
if(!vis[v])
{
q.push(v);
vis[v]=1;
}
}
}
}
}
int main()
{
cnt=1;
memset(fir,0,sizeof(fir));
int n,mx=0,u,v,w;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v+1,w);
mx=max(mx,v+1);
}
for(int i=1; i<=mx; i++)
{
add(i-1,i,0);
add(i,i-1,-1);
}
spfa(mx);//
printf("%d\n",dis[mx]);
return 0;
}
出纳员问题
题意 给几组测试样例,第一行是每小时最少需要的出纳员数量,然后给你申请者数量,表示在几时有一个人来申请
设r[i]为每小时最少需要的出纳员人数,t[i]为i时来应聘的人数
由于工作时间8小时确定,所以用sum数组表示t[i]的前缀和,
sum[i]-sum[i-8]>=第i个时刻需要的人数(r[i])
0<=sum[i]-sum[i-1]<=t[i]
当i<8的时候,i-8变成i-8+24→i+16
即sum[i]-sum[i+16]+x>=第i个时刻需要的人数(r[i])
sum[i]-sum[i-1]>=0;(差分隐含条件)
同时sum[i]-sum[i-1]<=在第i时刻应聘的人数(t[i])
sum[i]-sum[i+16]+sum[24]>=r[i];
统一一下不等式方向 跑最长路
sum[i]-sum[i-1]>=0;
sum[i-1]-sum[i]>=-t[i]
sum[i]-sum[i-8]>=r[i];
sum[i]-sum[i+16]+x>=r[i];
sum[24]-sum[0]>=x;(0时刻是不需要人的,所以x与sum[24]相等即可作为答案)
x即所求一天的最少出纳员数量,sum[24]-sum[0]
从小到大枚举x,用spfa判断是否可行
#include<stdio.h>
#include<string>
#include<iostream>
#include<string.h>
#include<queue>
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
const int M=30;
const int N=1000;
int fir[M],to[N],w[N],net[N],cnt;
int dis[M],vis[M],co[M],t[M],r[M];
void init()
{
memset(fir,0,sizeof(fir));
cnt=0;
memset(t,0,sizeof(t));
}
void add(int x,int y,int z)
{
net[++cnt]=fir[x];
fir[x]=cnt;
to[cnt]=y;
w[cnt]=z;
}
int spfa(int x)
{
queue<int>q;
mem(dis,-0x3f);
mem(co,0);
mem(vis,0);
int st=0;
while(!q.empty())
q.pop();
dis[st]=0;
vis[st]=1;
co[st]=1;
q.push(st);
while(!q.empty())
{
int u=q.front(),i;
q.pop();
vis[u]=0;
for(i=fir[u];i;i=net[i])
{
int v=to[i];
if(dis[v]<dis[u]+w[i])
{
dis[v]=dis[u]+w[i];
if(!vis[v])
{
vis[v]=1;
q.push(v);
co[v]++;
if(co[v]>24)
return 0;
}
}
}
}
return dis[24]==x;
}
int solve(int x)
{
memset(fir,0,sizeof(fir));
cnt=0;
for(int i=1;i<=24;i++)
{
add(i-1,i,0);
add(i,i-1,-t[i]);
if(i>8)
add(i-8,i,r[i]);
else
add(i+16,i,r[i]-x);
}
add(0,24,x);
return spfa(x);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
int x,flag=0,n;
for(int i=1;i<=24;i++)
scanf("%d",&r[i]);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
t[x+1]++;
}
// printf("%%%\n");
for(int i=0;i<=n;i++)
{
if(solve(i)){
printf("%d\n",i);
flag=1;
break;
}
}
if(!flag)
printf("No Solution\n");
}
return 0;
}
将所有权值取负跑最短路的代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int M=30;
const int N=1005;
int T,n,r[M],t[M],fir[M],to[N],nxt[N],w[N],num=0,dis[M],co[M],inf;
bool vis[M];
queue<int> q;
void init()
{
memset(fir,0,sizeof(fir));
memset(t,0,sizeof(t));
num=0;
}
void build(int u,int v,int ww)
{
num++;
to[num]=v;
nxt[num]=fir[u];
w[num]=ww;
fir[u]=num;
}
bool spfa(int x)
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(co,0,sizeof(co));
int st=24;
while(!q.empty()) q.pop();
q.push(st);
dis[st]=0;
vis[st]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=fir[u]; i; i=nxt[i])
{
int v=to[i];
if(dis[v]>dis[u]+w[i])
{
dis[v]=dis[u]+w[i];
if(!vis[v])
{
vis[v]=1;
q.push(v);
co[v]++;
if(co[v]>24) return 0;
}
}
}
}
return 1;
}
bool solve(int x)
{
memset(fir,0,sizeof(fir));
num=0;
for(int i=1; i<=24; i++)
{
build(i,i-1,0);
build(i-1,i,t[i]);
if(i>8) build(i,i-8,-r[i]);
else build(i,i+16,x-r[i]);
}
build(24,0,-x);
return spfa(x);
}
int main()
{
scanf("%d",&T);
while(T--)
{
init();
for(int i=1; i<=24; i++) scanf("%d",&r[i]);
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
int x;
scanf("%d",&x);
t[x+1]++;
}
int flag=0;
for(int i=0;i<=n;i++)
{
if(solve(i))
{
printf("%d\n",i);
flag=1;
break;
}
}
if(!flag) printf("No Solution\n");
}
return 0;
}