T1 二分图匹配 ,手贱匈牙利dfs写错了
T2 网络流 惨啊…………dinic手癌写错了,在往后增广的时候……应该用当前剩余流量……我敲成了在这个节点的所有流量……瞬间爆炸
//====================================================================================================================
T3 题意:定义两个有向图相似,当且仅当这两个图内任意两点间连通性相同(对于任意i,j∈V,如果原图i可以到达j,相似的图中i也可以到达j)。 给定一个有向图,求与它相似的图的最小边数和最大边数(没有重边和自环)(点数<=1000)
考虑若点集S(|S|>1)强连通,则边数最少时S为一个环(边数=|S|),边数最多时S为一个团(边数=|S|*(|S|-1))
缩了点后重新标号,新的图为一个DAG。显然求最大边数时可以直接把当前点能到达的所有点都连上边,随便搞搞就好了;而最小边数需要再瞎瘠薄搞一搞
对于求最小边数,原题简化为对于一个DAG,删掉尽量多的边使原图连通性不改变。
若有形如下图的结构,显然边(1,3)可以删去,
①---→②-----→③
└--------------↗
观察得,若可以删去边(i,j),当且仅当 【对于任意点 j 可以抵达的点 ,点 i 都可以在不经过边(i,j)的情况下到达】时。
记录可达性的话……直接用bitset压一下就好
目测得,应该尽量走最长路,所以把点按照【和 i 的距离】升序枚举一遍即可(可以预先拓扑排序一下)……正确性……感性理解【捂脸.gif】
三次才A,代码准确率有待提高
一周目30’:枚举时now写成了 i
二周目60‘:建新图直接用的邻接矩阵,虽然保证了原图没有重边,但缩点后的图很容易出现重边,于是如果用0..1的邻接矩阵来记录……入度出度可能会出事……
三周目AC,代码↓
#include<bits/stdc++.h>
#define MAXN 1005
#define MAXM 100005
using namespace std; int n,m;
struct t1{
int to,nxt;
}edge[MAXM]; int cnt_edge=0;
int fst[MAXN];
void addedge(int x,int y){
edge[++cnt_edge].to=y;
edge[cnt_edge].nxt=fst[x];
fst[x]=cnt_edge;
}
int col[MAXN],cnt_col;
int siz[MAXN];
int stk[MAXN],top=0;
int vis[MAXN],in_stk[MAXN];
int low[MAXN],dfn[MAXN],cnt_dfs=0;
void tarjan(int now){
vis[now]=in_stk[now]=1;
dfn[now]=low[now]=++cnt_dfs;
stk[++top]=now;
for(int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
int aim=edge[tmp].to;
if(!dfn[aim]) tarjan(aim),low[now]=min(low[now],low[aim]);
else{
if(in_stk[aim]) low[now]=min(low[now],dfn[aim]);
}
}
if(dfn[now]==low[now]){
++cnt_col;
for(;stk[top]^now;--top)
col[stk[top]]=cnt_col,in_stk[stk[top]]=0,++siz[cnt_col];
col[now]=cnt_col,in_stk[now]=0,--top,++siz[cnt_col];
}
}
int re_grp[MAXN][MAXN];
int ind[MAXN],oud[MAXN],dis[MAXN];
int que[MAXN],head,tail;
bitset<MAXN> reach[MAXN];
int cnt[MAXN];
void re_build(){
for(int now=1;now<=n;++now){
for(int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
int aim=edge[tmp].to;
if(col[aim]^col[now]&&!re_grp[col[now]][col[aim]])
re_grp[col[now]][col[aim]]=1,++ind[col[aim]],++oud[col[now]];
}
}
head=tail=0;
for(int i=1;i<=cnt_col;++i) if(!oud[i]) que[tail++]=i,dis[i]=1;
while(head^tail){
int now=que[head++];
for(int i=1;i<=cnt_col;++i){
if(re_grp[i][now]){
--oud[i];
if(oud[i]==0) que[tail++]=i,dis[i]=dis[now]+1;
}
}
}
}
void work1(){
int ans=0;
for(int i=0;i<cnt_col;++i){
int now=que[i];
reach[now][now]=1;
for(int j=i-1;~j;--j){
int aim=que[j];
if(re_grp[now][aim]){
/*
for(int k=1;k<=cnt_col;++k) printf(reach[now][k]? "1":"0");
puts("");
for(int k=1;k<=cnt_col;++k) printf(reach[aim][k]? "1":"0");
puts("\n");
*/
if(reach[now]==(reach[now]|reach[aim])) continue;
else ++ans,reach[now]|=reach[aim];
}
}
}
for(int i=1;i<=cnt_col;++i)
if(siz[i]>1) ans+=siz[i];
printf("%d ",ans);
}
void work2(){
int ans=0;
for(int i=0;i<cnt_col;++i){
int now=que[i];
ans+=siz[now]*(siz[now]-1);
for(int j=0;j<i;++j){
int aim=que[j];
if(reach[now][aim])
ans+=siz[now]*siz[aim];
}
}
printf("%d",ans);
}
int read_x,read_y;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
scanf("%d%d",&read_x,&read_y);
addedge(read_x,read_y);
}
for(int i=1;i<=n;++i)
if(!dfn[i]) tarjan(i);
/*
puts("");
for(int i=1;i<=n;++i)
printf("%d\n",col[i]),printf("siz = %d\n",siz[col[i]]);
//*/
re_build();
work1();
work2();
return 0;
}