[POJ3762 The Bonus Salary!]费用流

【题目大意】
给N个时间段,每个时间段只能用一次,然后有k天供你用这些时间段。
同一天里,时间段不能有重叠。
问最多能用到多少费用?
【算法分析】
先对所有时刻进行离散化。
然后每个时刻向下一个时刻连容量为k,费用为0的边。
接着对于每个区间 [L,R],对对应的时间连边L->R费用为区间费用,容量为1.
然后源点要退一个格子。
最后搞一个最大费用最大流就可以了。
【其它】
1CE,悲剧,POJ的iostream里不含sort函数。。。
【CODE】
#include #include #include #include #include using namespace std;
const int N=20000;
struct edge{int x,y,c,w;edge *op,*next;}g[N],*ls[N],*fa[N];
struct Node{int x,y,w;}p[N];
int n,k,tot,e,cost;
int lx[N],d[N],v[N],List[N];

void init(){
tot=0; e=0; memset(ls,0,sizeof(ls));
for (int i=1;i<=n;i++){
int h1,m1,s1,h2,m2,s2;
scanf("%d:%d:%d %d:%d:%d %d",&h1,&m1,&s1,&h2,&m2,&s2,&p[i].w);
p[i].x=h1*3600+m1*60+s1;
p[i].y=h2*3600+m2*60+s2;
lx[++tot]=p[i].x;
lx[++tot]=p[i].y;
}
}

void addedge(int x,int y,int c,int w){
g[++e].x=x; g[e].y=y; g[e].c=c; g[e].w=w; g[e].next=ls[x];
ls[x]=&g[e]; g[e].op=&g[e+1];
g[++e].x=y; g[e].y=x; g[e].c=0; g[e].w=-w; g[e].next=ls[y];
ls[y]=&g[e]; g[e].op=&g[e-1];
}

int Find(int x){
int l=1,r=tot,mid;
while (l mid=(l+r)/2;
if (x>lx[mid]) l=mid+1;
else r=mid;
}
return l;
}

void Lisan(){
sort(lx+1,lx+tot+1);
int tmp=tot,i; tot=0;
for (i=1;i<=tmp;i++)
if (!tot || lx[tot]!=lx[i]) lx[++tot]=lx[i];
for (i=1;i<=n;i++)
addedge(Find(p[i].x),Find(p[i].y),1,p[i].w);
for (i=1;i addedge(i,i+1,k,0);
addedge(0,1,k,0);
}

bool spfa(){
memset(d,200,sizeof(d));
memset(v,0,sizeof(v));
int head=0,tail=1;
List[1]=0; v[0]=1; d[0]=0;
while (head!=tail){
head++; if (head>=N) head=0;
for (edge *t=ls[List[head]];t;t=t->next)
if (t->c && d[t->x]+t->w>d[t->y]){
d[t->y]=d[t->x]+t->w;
fa[t->y]=t;
if (!v[t->y]){
v[t->y]=1;
tail++; if (tail>=N) tail=0;
List[tail]=t->y;
}
}
v[List[head]]=0;
}
if (d[tot]<=0) return false;
return true;
}

void change(){
int nf=0x7FFFFFFF;
for (int i=tot;i;i=fa[i]->x)
if (fa[i]->c cost+=nf*d[tot];
for (int i=tot;i;i=fa[i]->x){
fa[i]->c-=nf;
fa[i]->op->c+=nf;
}
}

void MCMF(){
cost=0;
while (spfa()) change();
}

int main(){
while (scanf("%d%d",&n,&k)!=EOF){
init();
Lisan();
MCMF();
printf("%dn",cost);
}
return 0;
}

[JSOI2010 满汉全席]2-sat

【题目链接】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1823
【算法分析】
对于每种材料,有做成满式和汉式两种情况,然后两者取且必须取一种。
而且约束条件是,(A做成XX式 or B做成yy式) = true。
逻辑运算符。。。很容易想到2-sat。
回想2-sat的建图,一条边(A,B)的意义是:如果你选了A,那么就必须选B。
恩,这个题目的逻辑式子转化成:加入你选了A的对立面,那么一定要选B啊。
恩,就这样。。。
【其它】很久没2-sat了,1Y。
【CODE】
#include #include #include const int N=1000;
const int E=1000000;
int n,m,e,times,ct,tot;
int lx[N],ly[N];
int fa[N],order[N];
bool v[N],Type;

struct Graph_t{
struct edge{int x,y;edge *next;}g[E],*ls[N];
void clr(){e=0; memset(ls,0,sizeof(ls));}
void addedge(int x,int y){
g[++e].x=x; g[e].y=y; g[e].next=ls[x]; ls[x]=&g[e];
}

void op(){
int tmp=e;
clr();
for (int i=1;i<=tmp;i++) addedge(g[i].y,g[i].x);
}

void dfs(int p){
v[p]=true;
for (edge *t=ls[p];t;t=t->next)
if (!v[t->y]) dfs(t->y);
if (Type) fa[p]=ct;
else order[++tot]=p;
}
}G;

int Get(){
char ch[20];
int x;
scanf("%s",ch);
sscanf(ch+1,"%d",&x);
if (ch[0]==’h’) x+=n;
return x;
}

void init(){
int i;
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++){
lx[i]=Get();
ly[i]=Get();
}
}

void build(){
G.clr();
int i,j;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++){
if (lx[j]==i+n) G.addedge(i,ly[j]);
if (ly[j]==i+n) G.addedge(i,lx[j]);
}
for (i=n+1;i<=n*2;i++)
for (j=1;j<=m;j++){
if (lx[j]==i-n) G.addedge(i,ly[j]);
if (ly[j]==i-n) G.addedge(i,lx[j]);
}
}

void SCC(){
memset(v,false,sizeof(v));
tot=0;
Type=false;
for (int i=1;i<=2*n;i++)
if (!v[i]) G.dfs(i);
Type=true;
G.op();
memset(v,false,sizeof(v));
for (int i=tot;i>=1;i–)
if (!v[order[i]]){
ct=order[i];
G.dfs(order[i]);
}
}

void output(){
bool ans=true;
for (int i=1;i<=n;i++)
if (fa[i]==fa[i+n]) ans=false;
if (ans) puts("GOOD");
else puts("BAD");
}

int main(){
int Tc,i;
scanf("%d",&Tc);
for (i=1;i<=Tc;i++){
init();
build();
SCC();
output();
}
}

[ZJOI2010 network 网络扩容]费用流

【题目地址】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1834
【算法分析】
很裸啊。
第一问直接最大流,但是我写得是边权全部为0的费用流= =,方便第二问。。。
第二问的话,就是每条边加多一条容量无限,费用为给定费用的边。
然后加多一个超汇点,n向它连一个maxflow+K的边。
最后输出费用即可。
【其它】1Y,水过留痕。。。
【CODE】
#include #include const int N=1555;
const int E=5555*4;
const int INF=0x7FFFFFFF/2-55;
struct edge{int x,y,c,w;edge *next,*op;}g[E],*ls[N],*fa[N];
int n,m,q,e,flow,cost;
int lx[E],ly[E],lc[E],lw[E],L[N],d[N],v[N];

void add(int x,int y,int c,int w){
g[++e].x=x; g[e].y=y; g[e].c=c; g[e].w=w;
g[e].next=ls[x]; ls[x]=&g[e]; g[e].op=&g[e+1];
g[++e].x=y; g[e].y=x; g[e].c=0; g[e].w=-w;
g[e].next=ls[y]; ls[y]=&g[e]; g[e].op=&g[e-1];
}

void push_back(){
for (int i=2;i<=e;i+=2){
edge *t=&g[i];
t->op->c+=t->c;
t->c=0;
}
}

bool spfa(){
int head=0,tail=1;
for (int i=1;i<=n;i++){
v[i]=0;
d[i]=INF;
}
v[1]=1; d[1]=0; L[1]=1;
while (head!=tail){
head++; if (head>=N) head=0;
for (edge *t=ls[L[head]];t;t=t->next)
if (t->c && d[t->x]+t->w d[t->y]=d[t->x]+t->w;
fa[t->y]=t;
if (!v[t->y]){
v[t->y]=1;
tail++; if (tail>=N) tail=0;
L[tail]=t->y;
}
}
v[L[head]]=0;
}
if (d[n]==INF) return false;
return true;
}

void change(){
int nf=INF;
for (int i=n;i!=1;i=fa[i]->x)
if (fa[i]->c flow+=nf; cost+=d[n]*nf;
for (int i=n;i!=1;i=fa[i]->x){
fa[i]->c-=nf;
fa[i]->op->c+=nf;
}
}

void mincost_maxflow(){
flow=cost=0;
while (spfa()) change();
}

int main(){
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=m;i++){
scanf("%d%d%d%d",&lx[i],&ly[i],&lc[i],&lw[i]);
add(lx[i],ly[i],lc[i],0);
}
mincost_maxflow();
printf("%d ",flow);
for (int i=1;i<=m;i++)
add(lx[i],ly[i],INF,lw[i]);
add(n,n+1,flow+q,0);
n++;
push_back();
mincost_maxflow();
printf("%dn",cost);
}

[JSOI2010 Group 部落划分]并差集、排序

【题目链接】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1821
【算法分析】
就是把边权从小到大排序,然后从前面搞下来,用并差集判断剩下的独立块有多少个?
如果【其它】
WA了N遍= =。
if (Num写成了
if (Num头脑有点不清醒啊。。。
【CODE】
#include #include #include #include #define sqr(x) ((x)*(x))
const int N=1005;
struct Point{int x,y;}a[N];
struct edge{int x,y,w;}g[N*N];
int n,part,m;
int f[N];

int dis(Point A,Point B){
return sqr(A.x-B.x)+sqr(A.y-B.y);
}

void input(){
scanf("%d%d",&n,&part);
for (int i=1;i<=n;i++)
scanf("%d%d",&a[i].x,&a[i].y);
m=0;
for (int i=1;i for (int j=i+1;j<=n;j++){
g[m].x=i;
g[m].y=j;
g[m].w=dis(a[i],a[j]);
++m;
}
}

int cmp(const void *A,const void *B){
return ((edge*)A)->w-((edge*)B)->w;
}

int GF(int k){
if (f[k]==k) return k;
else return f[k]=GF(f[k]);
}

int solve(){
int Num=n;
for (int i=1;i<=n;i++) f[i]=i;
for (int i=0;;i++){
edge &p=g[i];
if (GF(p.x)!=GF(p.y)){
f[f[p.x]]=f[p.y];
Num–;
if (Num }
}
}

int main(){
input();
qsort(g,m,sizeof(edge),cmp);
printf("%.2lfn",sqrt(1.0*solve()));
}

[Sdoi2010 所驼门王的宝藏]强连通分量、猥琐优化

【题目链接】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1924
【算法分析】
一开始就YY裸的强连通,但是如果他们都在同一行,而且都是1的话,边数将达到n*n的级别。
然后除了这个猥琐数据,其它的一般好像没啥问题。
于是我就把在同一行的,都是1的用k条边直接连成一个圈。
在同一列的,都是2的,也用k条边直接连成一个圈。
(k表示这一行(列)为1(2)的点的个数。)
然后暴力SCC。
最后dp输出即可。
【其它】
来BS我吧。。。再一次全世界最慢。终于把Sdoi第一轮的6题都AC了~
1 23185 root 7804K 1012MS G++ 3.07K 2010-05-14 13:51:35 2 24544 maja 35592K 1041MS Pascal 3.82K 2010-05-20 09:12:35 3 24545 wu3412790 35592K 1057MS Pascal 3.82K 2010-05-20 09:13:00 4 24621 colonnello 15012K 1153MS Pascal 8.31K 2010-05-20 16:37:08 5 24566 Ksloverainboy 35700K 1167MS Pascal 5.66K 2010-05-20 12:56:19 6 23589 nehzilrz 20024K 1183MS G++ 3.71K 2010-05-16 13:52:20 7 23192 FDhyc 10932K 1232MS Pascal 5.61K 2010-05-14 13:57:22 8 23362 oimaster 11568K 1356MS G++ 3.91K 2010-05-15 15:52:05 9 24880 _gXX 36740K 1370MS Pascal 5.06K 2010-05-21 20:30:14 10 24096 tracyhenry 44520K 1371MS Pascal 5.51K 2010-05-18 19:01:05 11 23341 jsn1993 11968K 1373MS G++ 3.17K 2010-05-15 07:54:22 12 24554 cly 48776K 1574MS Pascal 7.06K 2010-05-20 10:29:23 13 24512 bonism 57724K 1636MS G++ 3.76K 2010-05-20 07:57:28 14 24901 edward_mj 6652K 1638MS G++ 4.48K 2010-05-21 21:46:52 【CODE】
#include #include #include const int E=2000005;
const int N=100005;
const int px[8]={-1,-1,-1, 0, 0, 1, 1, 1};
const int py[8]={-1, 0, 1,-1, 1,-1, 0, 1};
int n,tot,cnt,Lt;
int fa[N],order[N],List[N],F[N];
bool v[N];
struct Node{int x,y,T,w,pos;}a[N];
struct edge{int x,y;edge *next;};
struct Gtp{
int e;
edge g[E],*ls[100005];
void init(){e=0; for (int i=0;i void add(int x,int y){
if (!x || !y || x==y) return;
g[++e].x=x; g[e].y=y; g[e].next=ls[x]; ls[x]=&g[e];
}

void op(){
int tmp=e,i;
init();
for (i=1;i<=tmp;i++)
add(g[i].y,g[i].x);
}

void Turn_fa(){
int tmp=e,i;
init();
for (i=1;i<=tmp;i++)
add(fa[g[i].x],fa[g[i].y]);
}

void dfs(int p,bool Type){
v[p]=true;
if (Type) fa[p]=cnt;
for (edge *t=ls[p];t;t=t->next)
if (!v[t->y]) dfs(t->y,Type);
if (!Type) order[++tot]=p;
}
}G;

void input(){
int r,c,i;
scanf("%d%d%d",&n,&r,&c);
for (i=1;i<=n;i++){
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].T);
a[i].pos=i;
a[i].w=0;
fa[i]=i;
}
}

int cmpR(const void *A,const void *B){
return ((Node*)A)->x-((Node*)B)->x;
}
int cmpC(const void *A,const void *B){
return ((Node*)A)->y-((Node*)B)->y;
}
int cmpFree(const void *A,const void *B){
if (((Node*)A)->x!=((Node*)B)->x) return ((Node*)A)->x-((Node*)B)->x;
return ((Node*)A)->y-((Node*)B)->y;
}
int cmpdp(const void *A,const void *B){
return ((Node*)A)->pos-((Node*)B)->pos;
}

struct R_Function{
void deal(){
qsort(a+1,n,sizeof(Node),cmpR);
int i,j,k,st,pre;
for (i=1;i<=n;i=j+1){
for (j=i;j for (k=i,st=0,pre=0;k<=j;k++)
if (a[k].T==1){
if (!st) st=a[k].pos;
else G.add(pre,a[k].pos);
pre=a[k].pos;
}
G.add(pre,st);
for (k=i;k<=j;k++)
if (a[k].T!=1)
G.add(st,a[k].pos);
}
}
}R;

struct C_Function{
void deal(){
qsort(a+1,n,sizeof(Node),cmpC);
int i,j,k,st,pre;
for (i=1;i<=n;i=j+1){
for (j=i;j for (k=i,st=0,pre=0;k<=j;k++)
if (a[k].T==2){
if (!st) st=a[k].pos;
else G.add(pre,a[k].pos);
pre=a[k].pos;
}
G.add(pre,st);
for (k=i;k<=j;k++)
if (a[k].T!=2)
G.add(st,a[k].pos);
}
}
}C;

struct Free_Function{
int Find(int x,int y){
int l=1,r=n,mid;
while (l mid=(l+r)/2;
if (a[mid].x else r=mid;
}
if (a[l].x==x && a[l].y==y) return a[l].pos;
return 0;
}

void deal(){
qsort(a+1,n,sizeof(Node),cmpFree);
int i,j;
for (i=1;i<=n;i++)
if (a[i].T==3)
for (j=0;j<8;j++)
G.add(a[i].pos,Find(a[i].x+px[j],a[i].y+py[j]));
}
}Free;

void SCC(){
G.Turn_fa();
memset(v,false,sizeof(v));
int i,j; tot=Lt=0;
for (i=1;i<=n;i++)
if (!v[i])
G.dfs(i,false);
G.op();
memset(v,false,sizeof(v));
for (j=tot;j>=1;j–){
i=order[j];
if (!v[i]){
cnt=i;
List[++Lt]=i;
G.dfs(i,true);
}
}
G.op();
G.Turn_fa();
}

void dp(){
qsort(a+1,n,sizeof(Node),cmpdp);
memset(F,0,sizeof(F));
int i,j,ans=0;
for (i=1;i<=n;i++) a[fa[i]].w++;
for (j=1;j<=Lt;j++){
i=List[j];
F[i]+=a[i].w;
for (edge *t=G.ls[i];t;t=t->next)
if (F[i]>F[t->y]) F[t->y]=F[i];
if (F[i]>ans) ans=F[i];
}
printf("%dn",ans);
}

int main(){
input();
R.deal();
C.deal();
Free.deal();
SCC();
dp();
}