201709-2 公共钥匙盒
问题描述
有一个学校的老师共用N个教室,按照规定,所有的钥匙都必须放在公共钥匙盒里,老师不能带钥匙回家。每次老师上课前,都从公共钥匙盒里找到自己上课的教室的钥匙去开门,上完课后,再将钥匙放回到钥匙盒中。
钥匙盒一共有N个挂钩,从左到右排成一排,用来挂N个教室的钥匙。一串钥匙没有固定的悬挂位置,但钥匙上有标识,所以老师们不会弄混钥匙。
每次取钥匙的时候,老师们都会找到自己所需要的钥匙将其取走,而不会移动其他钥匙。每次还钥匙的时候,还钥匙的老师会找到最左边的空的挂钩,将钥匙挂在这个挂钩上。如果有多位老师还钥匙,则他们按钥匙编号从小到大的顺序还。如果同一时刻既有老师还钥匙又有老师取钥匙,则老师们会先将钥匙全还回去再取出。
今天开始的时候钥匙是按编号从小到大的顺序放在钥匙盒里的。有K位老师要上课,给出每位老师所需要的钥匙、开始上课的时间和上课的时长,假设下课时间就是还钥匙时间,请问最终钥匙盒里面钥匙的顺序是怎样的?
输入格式
输入的第一行包含两个整数N, K。
接下来K行,每行三个整数w, s, c,分别表示一位老师要使用的钥匙编号、开始上课的时间和上课的时长。可能有多位老师使用同一把钥匙,但是老师使用钥匙的时间不会重叠。
保证输入数据满足输入格式,你不用检查数据合法性。
输出格式
输出一行,包含N个整数,相邻整数间用一个空格分隔,依次表示每个挂钩上挂的钥匙编号。
样例输入
5 2
4 3 3
2 2 7
样例输出
1 4 3 2 5
这个题需要根据不同的时间点 拿走钥匙 归还钥匙,每个操作有一个时间点,直接记录这个时间点要借还是还几号钥匙即可,数据量较小2000。都存放在vector中,直接对钥匙数组进行操作即可。分析问题要找到关键的影响因素。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
struct node
{
int w,c;
int ok;
node(int w,int c,int ok):w(w),c(c),ok(ok){}
//注意学会用结构体中的析构函数 括冒分括弧
};
vector<node> v;
bool cmp(node a,node b)
{
if(a.c!=b.c) return a.c<b.c;
else if(a.ok!=b.ok) return a.ok>b.ok;
else return a.w<b.w;
}
int main()
{
int n,k,x;
scanf("%d%d",&n,&k);
int w,s,c;
for(int i=0;i<k;i++){
scanf("%d%d%d",&w,&s,&c);
v.push_back(node(w,s,0));//直接填写 node()
v.push_back(node(w,s+c,1));
}
sort(v.begin(),v.end(),cmp);
int a[n+5];
for(int i=1;i<=n;i++)
a[i]=i;
for(int i=0;i<v.size();i++){
if(v[i].ok==0){
for(int j=1;j<=n;j++){
if(a[j]==v[i].w){
a[j]=0;break;
}
}
}
else{
for(int j=1;j<=n;j++){
if(a[j]==0){
a[j]=v[i].w;break;
}
}
}
}
for(int i=1;i<=n;i++){
if(i==1) printf("%d",a[i]);
else printf(" %d",a[i]);
}
printf("\n");
return 0;
}
201809-4再卖菜
2*a1<=(x1+x2)<=2*a1+1
3*a2<=(x1+x2+x3)<=3*a2+2
2*an<=(x(n-1)+xn)<=2*an+1
但是呢?差分约束不是都两个么 ,这个属于三个,那么考虑s=x0+x1+x2+....xn,之后就又有了一组式子,这个x0必然为0
2*a1<=s2-s0<=2*a1+1
3*a2<=s3-s0<=3*a2+2
3*a3<=s4-s1<=3*a3+2
2*an<=sn-s(n-2)<=2*an+1
之后就是差分约束不是方向统一么,那么就统一用>=吧,之后式子拆解成两个
s2-s0>=2*a1 s0-s2>=-2*a1-1
s3-s0>=3*a3 s0-s3>=-3*a2-2
sn-s(n-2)>=2*an s(n-2)-sn>=-2*an-1
也就是sj-si>=x,建立从i到j有一条x的边,之后记住差分约束就是<=求解最短路,>=求解最长路,然后这个题拿spfa跑最长路,最后还有一点要注意的就是各个x都要是正整数,也就是还得需要建立一个约束条件,si-s(i-1)=xi,因为xi>=1,所以si-s(i-1)>=1
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e3+50;
const int maxn=5e2+50;
struct edge{
int v,w,next;
};
edge edges[maxm];
int head[maxn],tot;
void add_edges(int u,int v,int w)
{
edges[tot].v=v;
edges[tot].w=w;
edges[tot].next=head[u];
head[u]=tot++;
}
int n;
bool vis[maxn];
int cnt[maxn];
int dist[maxn];
bool spfa()
{
queue<int>q;
for(int i=0;i<n;i++){
q.push(i);
vis[i]=false;dist[i]=0;cnt[i]=1;
}
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];~i;i=edges[i].next){
int v=edges[i].v;
if(dist[v]<dist[u]+edges[i].w){
dist[v]=dist[u]+edges[i].w;
if(!vis[v]){
vis[v]=1;
q.push(v);
if(++cnt[v]>n){
return false;
}
}
}
}
}
return true;
}
int a[maxn];
int main()
{
memset(head,-1,sizeof(head));
tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<n-2;i++){
add_edges(i+3,i,-(a[i+2]*3+2));
add_edges(i,i+3,a[i+2]*3);
}
add_edges(2,0,-(a[1]*2+1));add_edges(0,2,a[1]*2);
add_edges(n,n-2,-(a[n]*2+1));add_edges(n-2,n,a[n]*2);
for(int i=1;i<=n;i++){
add_edges(i-1,i,1);
}
if(spfa()){
a[1]=dist[1];
for(int i=2;i<n+1;i++){
a[i]=dist[i]-dist[i-1];
}
printf("%d",a[1]);
for(int i=2;i<n+1;i++){
printf(" %d",a[i]);
}
}
return 0;
}