HDU - 2196
算法:树的直径,树形DP
注释:dist[i][0]表示向下最长距离,dist[i][1]表示向下次长距离,dist[i][2]表示反向最长距离
1)先按求树的直径的方法计算出每个节点向下的最长距离和次长距离,注意应该记录达到最长距离最经过的儿子节点,以方便后边方向距离的计算。状态转移公式为:
if(dist[u][0]
{
longest[u]=v;
dist[u][1]=dist[u][0];
dist[u][0]=dist[v][0]+w;
}
else if(dist[u][1]dist[u][1]=dist[v][0]+w;
DP顺序为先计算儿子节点,再计算父节点。
2)在求该节点经过父节点的反向最长距离,注意不应该用父节点能到达的最大距离,因为可能出现重复路径。状态转移公式为:
if(v==longest[u])dist[v][2]=max(dist[u][2],dist[u][1])+w;
else dist[v][2]=max(dist[u][2],dist[u][0])+w;
DP顺序先计算父节点,再计算子节点。
#include
#include
#include
#define N 10010
#define ll long long
using namespace std;
int first[N],nex[N<<1],ord[N<<1],vul[N<<1],cnt;
ll dist[N][3],longest[N];
void add(int u,int v,ll w)
{
nex[++cnt]=first[u];
ord[cnt]=v;
vul[cnt]=w;
first[u]=cnt;
}
ll max(ll a,ll b)
{
return a>b?a:b;
}
void dp1(int u,int father)
{
//cout<
int i,v,w;
for(i=first[u];i;i=nex[i])
{
v=ord[i];
w=vul[i];
if(v==father)continue;
dp1(v,u);
if(dist[u][0]<dist[v][0]+w)
{
longest[u]=v;
dist[u][1]=dist[u][0];
dist[u][0]=dist[v][0]+w;
}
else if(dist[u][1]<dist[v][0]+w)
dist[u][1]=dist[v][0]+w;
}
}
void dp2(int u,int father)
{
int v,w,i;
for(i=first[u];i;i=nex[i])
{
v=ord[i];
w=vul[i];
if(v==father)continue;
if(v==longest[u])dist[v][2]=max(dist[u][2],dist[u][1])+w;
else dist[v][2]=max(dist[u][2],dist[u][0])+w;
dp2(v,u);
}
}
int main()
{
ll i,u,n,v,w;
while(cin>>n&&n!=0)
{
memset(dist,0,sizeof(dist));
memset(first,0,sizeof(first));
memset(longest,0,sizeof(longest));
cnt=0;
for(u=2;u<=n;u++)
{
cin>>v>>w;
add(u,v,w);
add(v,u,w);
}
dp1(1,0);
dp2(1,0);
for(u=1;u<=n;u++)
cout<<max(dist[u][2],dist[u][0])<<endl;
}
return 0;
}
CF1245D
算法:最小生成树
注释:本题考验抽象思维
#include
#include
#include
#include
#define N 2010
#define M 5000010
#define ll long long
using namespace std;
struct point{
int x,y;
}p[N];
struct edge{
int u,v;
ll w;
}e[M],con[N];
int c[N],k[N],f[N],cnt;
int vn=0,build[N],en=0;
ll ans;
bool cmp(const edge &a,const edge &b)
{
return a.w<b.w;
}
void init(int n)
{
for(int i=0;i<=n;i++)
f[i]=i;
}
int find(int u)
{
if(f[u]==u)return u;
return find(f[u]);
}
ll dis(int i,int j)
{
return (abs(p[i].x-p[j].x)+abs(p[i].y-p[j].y));
}
int main()
{
int n,m=0;
cin>>n;
init(n);
for(int i=1;i<=n;i++)
cin>>p[i].x>>p[i].y;
for(int i=1;i<=n;i++)
{
cin>>c[i];
e[m].u=i;
e[m].v=0;
e[m++].w=c[i];
}
for(int i=1;i<=n;i++)
cin>>k[i];
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
e[m].u=i;
e[m].v=j;
//cout<
e[m++].w=dis(i,j)*(k[i]+k[j]);
}
}
//cout<
sort(e,e+m,cmp);
for(int i=0;i<m;i++)
{
//cout<
int u=find(e[i].u);
int v=find(e[i].v);
if(u!=v)
{
if(e[i].v==0)
{
build[++vn]=e[i].u;
}
else
{
con[++en].u=e[i].u;
con[en].v=e[i].v;
}
f[u]=v;
ans+=e[i].w;
cnt++;
}
if(cnt==n)break;
}
cout<<ans<<endl;
cout<<vn<<endl;
for(int i=1;i<=vn;i++)
cout<<build[i]<<" ";
cout<<endl<<en<<endl;
for(int i=1;i<=en;i++)
cout<<con[i].u<<" "<<con[i].v<<endl;
return 0;
}
Codeforces 337D
算法:树的直径,树形DP
注释:
#include
#include
#include
#define N 100010
#define MINN -0x3f3f3f3f
using namespace std;
int dist[N][3],longest[N];
int first[N],nex[N<<1],ord[N<<1],cnt=0;
bool p[N];
int max(int a,int b)
{
return a>b?a:b;
}
void add(int u,int v)
{
nex[++cnt]=first[u];
ord[cnt]=v;
first[u]=cnt;
}
void dp1(int u,int father)
{
int v,i;
if(p[u])dist[u][0]=dist[u][2]=0;
for(i=first[u];i;i=nex[i])
{
v=ord[i];
if(v==father)continue;
dp1(v,u);
if(dist[u][0]<dist[v][0]+1)
{
longest[u]=v;
dist[u][1]=dist[u][0];
dist[u][0]=dist[v][0]+1;
}
else if(dist[u][2]<dist[v][0]+1)
{
dist[u][2]=dist[v][0]+1;
}
}
}
void dp2(int u,int father)
{
int v,i;
for(i=first[u];i;i=nex[i])
{
v=ord[i];
if(v==father)continue;
if(dist[v][0]+1==dist[u][0])
{
dist[v][2]=max(dist[u][2],dist[u][1])+1;
}
else
dist[v][2]=max(dist[u][0],dist[u][2])+1;
dp2(v,u);
}
}
int main()
{
int n,m,d,i,u,v,x,tot=0;
cin>>n>>m>>d;
for(i=1;i<=n;i++)
dist[i][0]=dist[i][1]=dist[i][2]=MINN;
for(i=1;i<=m;i++)
{
cin>>x;
p[x]=true;
}
for(i=1;i<n;i++)
{
cin>>u>>v;
add(u,v);
add(v,u);
}
dp1(1,0);
dp2(1,0);
//for(i=1;i<=n;i++)
//cout<
for(i=1;i<=n;i++)
{
if(i==1)
{
if(max(dist[i][0],dist[i][1])<=d)tot++;
}
else if(max(dist[i][0],dist[i][2])<=d)tot++;
}
cout<<tot<<endl;
return 0;
}
第一周提高 H - 8
算法:树的直径,树形DP
注释:
#include
#include
#include
#define N 200010
using namespace std;
int first[N],nex[N<<1],ord[N<<1],cnt;
int dist[N][4],p[N][4],longest[N],maxn,res[3];
void add(int u,int v)
{
nex[++cnt]=first[u];
ord[cnt]=v;
first[u]=cnt;
}
void init(int n)
{
int i;
memset(dist,0,sizeof(dist));
for(i=0;i<=n;i++)
p[i][0]=p[i][1]=p[i][2]=p[i][3]=i;
}
int max(int a,int b)
{
return a>b?a:b;
}
void dfs1(int u,int father)
{
int v,i;
for(i=first[u];i;i=nex[i])
{
v=ord[i];
if(v==father)continue;
dfs1(v,u);
if(dist[u][0]<dist[v][0]+1)
{
longest[u]=v;
dist[u][2]=dist[u][1];
p[u][2]=p[u][1];
dist[u][1]=dist[u][0];
p[u][1]=p[u][0];
dist[u][0]=dist[v][0]+1;
p[u][0]=p[v][0];
}
else if(dist[u][1]<dist[v][0]+1)
{
dist[u][2]=dist[u][1];
p[u][2]=p[u][1];
dist[u][1]=dist[v][0]+1;
p[u][1]=p[v][0];
}
else if(dist[u][2]<dist[v][0]+1)
{
dist[u][2]=dist[v][0]+1;
p[u][2]=p[v][0];
}
}
}
void dfs2(int u,int father)
{
int v,i;
for(i=first[u];i;i=nex[i])
{
v=ord[i];
if(v==father)continue;
if(v==longest[u])
{
if(dist[u][3]>dist[u][1])
{
dist[v][3]=dist[u][3]+1;
p[v][3]=p[u][3];
}
else
{
dist[v][3]=dist[u][1]+1;
p[v][3]=p[u][1];
}
}
else
{
if(dist[u][3]>dist[u][0])
{
dist[v][3]=dist[u][3]+1;
p[v][3]=p[u][3];
}
else
{
dist[v][3]=dist[u][0]+1;
p[v][3]=p[u][0];
}
}//dist[v][3]=max(dist[u][0],dist[u][3])+1;
dfs2(v,u);
}
}
bool judge(int u)
{
if((p[u][0]!=p[u][1])&&((p[u][1]!=p[u][2])||(p[u][1]!=p[u][3]))&&((p[u][0]!=p[u][2])||(p[u][0]!=p[u][3])))
return 1;
else return 0;
}
int main()
{
int n,u,v,i;
cin>>n;
init(n);
for(i=1;i<n;i++)
{
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs1(1,0);
dfs2(1,0);
for(int i=1;i<=n;i++)
{
//cout<
if(maxn<dist[i][0]+dist[i][1]+max(dist[i][2],dist[i][3])&&judge(i))
{
maxn=dist[i][0]+dist[i][1]+max(dist[i][2],dist[i][3]);
res[0]=p[i][0];
res[1]=p[i][1];
res[2]=(dist[i][2]>dist[i][3]?p[i][2]:p[i][3]);//当相等时,优先选择父节点
}
}
cout<<maxn<<endl;
cout<<res[0]<<" "<<res[1]<<" "<<res[2];
return 0;
}
UVA-11624
算法:BFS
注释:
#include
#include
#include
#include
#include
#define N 1010
using namespace std;
struct step{
int x;
int y;
int s;
}temp;
queue<step>q;
char map[N][N];
bool vis[N][N];
int nx[4]={0,1,0,-1},ny[4]={1,0,-1,0},r,c,t,fmap[N][N];
void bfsf()
{
step u,v;
while(!q.empty())
{
u=q.front();
//cout<
q.pop();
for(int i=0;i<=3;i++)
{
v.x=u.x+nx[i];
v.y=u.y+ny[i];
v.s=u.s+1;
if(v.x==0||v.x>r||v.y==0||v.y>c)continue;
else if(map[v.x][v.y]=='.'&&vis[v.x][v.y]==false)
{
vis[v.x][v.y]=true;
fmap[v.x][v.y]=v.s;
q.push(v);
}
}
}
}
int bfs(int sx,int sy)
{
step u,v;
vis[sx][sy]=true;
u.x=sx;
u.y=sy;
u.s=0;
q.push(u);
while(!q.empty())
{
u=q.front();
//cout<
q.pop();
for(int i=0;i<=3;i++)
{
v.x=u.x+nx[i];
v.y=u.y+ny[i];
v.s=u.s+1;
if(v.x==0||v.x>r||v.y==0||v.y>c)return v.s;
else if(map[v.x][v.y]=='.'&&vis[v.x][v.y]==false)
{
vis[v.x][v.y]=true;
//cout<
if(fmap[v.x][v.y]<=v.s)
{
//cout<
continue;
}
q.push(v);
}
}
}
return -1;
}
void init()
{
memset(vis,0,sizeof(vis));
while(!q.empty())q.pop();
}
int main()
{
//freopen("1.txt","r",stdin);
//freopen("2.txt","w",stdout);
cin>>t;
int b=0;
while(t--)
{
b++;
init();
memset(fmap,111,sizeof(fmap));
int sx,sy;
cin>>r>>c;
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
{
cin>>map[i][j];
if(map[i][j]=='F')
{
fmap[i][j]=0;
temp.x=i;
temp.y=j;
temp.s=0;
q.push(temp);
}
if(map[i][j]=='J')
{
sx=i;
sy=j;
}
}
bfsf();
init();
int res=bfs(sx,sy);
if(res==-1)cout<<"IMPOSSIBLE"<<endl;
else cout<<res<<endl;
}
return 0;
}
UVA-10047
算法:BFS
注释:
#include
#include
#include
#include
using namespace std;
struct state{
int x,y,d,c;
int s;
}s,t;
int f[26][26][4][5],n,m,nx[4]={-1,0,1,0},ny[4]={0,1,0,-1};
bool vis[26][26][4][5];//检查时应该注意数组的大小开的是否合适,尽量开大一点
char map[26][26];
queue<state>q;
void init()
{
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
while(!q.empty())q.pop();
}
void is_push(state v)
{
if(vis[v.x][v.y][v.d][v.c]==0)
{
vis[v.x][v.y][v.d][v.c]=1;
q.push(v);
}
}
int bfs()
{
state u,v;
s.s=0;
s.c=0;
s.d=0;
vis[s.x][s.y][s.d][s.c]=1;
q.push(s);
while(!q.empty())
{
u=q.front();
q.pop();
v.s=u.s+1;
//向下一个方向转
v.x=u.x;
v.y=u.y;
v.c=u.c;
v.d=(u.d+5)%4;
is_push(v);
//向上一个方向转
v.x=u.x;
v.y=u.y;
v.c=u.c;
v.d=(u.d+3)%4;
is_push(v);
//向当前方向走一格
v.x=u.x+nx[u.d];
v.y=u.y+ny[u.d];
v.c=(u.c+1)%5;
v.d=u.d;
if(v.x>0&&v.y>0&&v.x<=n&&v.y<=m&&map[v.x][v.y]!='#')
{
if(v.x==t.x&&v.y==t.y&&v.c==0)
return v.s;
is_push(v);
}
}
return -1;
}
int main()
{
int cnt=0;
while(cin>>n>>m&&n&&m)
{
cnt++;
init();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>map[i][j];
if(map[i][j]=='S')
{
s.x=i;
s.y=j;
}
if(map[i][j]=='T')
{
t.x=i;
t.y=j;
}
}
if(cnt!=1)cout<<endl;
cout<<"Case #"<<cnt<<endl;
int res=bfs();
if(res!=-1)cout<<"minimum time = "<<res<<" sec"<<endl;
else cout<<"destination not reachable"<<endl;
}
return 0;
}
LibreOJ - 2436
算法:拓扑排序,spfa,差分约束
注释:
#include
#include
#include
#include
#define ll long long
#define N 100010
#define K 100010
using namespace std;
struct edge{
int next;
int to;
ll w;
}e[K<<2];
ll first[N],cnt,dis[N],num[N];
bool vis[N];
queue<int>q;
void add(int u,int v,int w)
{
e[++cnt].next=first[u];
e[cnt].to=v;
e[cnt].w=w;
first[u]=cnt;
}
void init()
{
cnt=0;
memset(first,-1,sizeof(first));
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
while(!q.empty())q.pop();
}
int spfa(int s,int n)
{
dis[s]=0;
vis[s]=1;
num[s]++;
q.push(s);
int u,v,w;
while(!q.empty())
{
u=q.front();
vis[u]=0;
q.pop();
for(int i=first[u];i+1;i=e[i].next)
{
v=e[i].to;
w=e[i].w;
if(dis[v]<dis[u]+w)
{
dis[v]=dis[u]+w;
if(!vis[v])
{
q.push(v);
vis[v]=1;
}
num[v]++;
if(num[v]>n)return -1;
}
}
}
return 1;
}
int min(int a,int b)
{
return a<b?a:b;
}
int main()
{
//freopen("3.in","r",stdin);
init();
ll n,k,x,a,b,tot=0,minn=0;
cin>>n>>k;
for(int i=0;i<k;i++)
{
cin>>x>>a>>b;
if(x==1)
{
add(b,a,0);
add(a,b,0);
}
else if(x==2)
{
if(a==b){cout<<-1;return 0;}//特殊情况的考虑
add(a,b,1);
}
else if(x==3) add(b,a,0);
else if(x==4)
{
if(a==b){cout<<-1;return 0;}
add(b,a,1);
}
else if(x==5) add(a,b,0);
}
for(int i=n;i>=1;i--)
add(0,i,1);
if(spfa(0,n)==-1)
cout<<-1;
else
{
for(int i=1;i<=n;i++)
tot+=dis[i];
//cout<
cout<<tot;
}
return 0;
}
UVALive - 4255
算法:前缀和,差分约束,拓扑排序
注释:
#include
#include
#include
#include
#include
#define N 20
using namespace std;
struct edge{
int next,to;
}e[N*N*2];
struct point{
int num,pri;
}q[N];
int sum[N],n,first[N],cnt,inum[N];
char pos[N][N];
int head,tail;
void add(int u,int v)
{
e[++cnt].next=first[u];
e[cnt].to=v;
first[u]=cnt;
}
void init()
{
memset(first,-1,sizeof(first));
memset(sum,0,sizeof(sum));
memset(inum,0,sizeof(inum));
head=tail=cnt=0;
}
int main()
{
int t,x,zero;
point u,v;
cin>>t;
while(t--)
{
init();
cin>>n;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
cin>>pos[i][j];
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
if(pos[i][j]=='+')
{
add(i-1,j);
inum[j]++;
}
else if(pos[i][j]=='-')
{
add(j,i-1);
inum[i-1]++;
}
}
}
/*for(int i=0;i<=n;i++)
{
cout<
for(int i=0;i<=n;i++)
if(!inum[i])
{
q[tail].num=i;
q[tail].pri=0;
tail++;
}
point temp;
while(head<tail)
{
u=q[head++];
for(int i=first[u.num];i+1;i=e[i].next)
{
v.num=e[i].to;
inum[v.num]--;
if(!inum[v.num])
{
v.pri=u.pri+1;
q[tail++]=v;
}
}
}
for(int i=0;i<=n;i++)
if(q[i].num==0)
{
zero=i;
break;
}
for(int i=zero-1;i>=0;i--)
{
if(q[i].pri!=q[i+1].pri)
sum[q[i].num]=sum[q[i+1].num]-1;
else
sum[q[i].num]=sum[q[i+1].num];
}
for(int i=zero+1;i<=n;i++)
{
if(q[i].pri!=q[i-1].pri)
sum[q[i].num]=sum[q[i-1].num]+1;
else
sum[q[i].num]=sum[q[i-1].num];
}
for(int i=1;i<=n;i++)
{
cout<<sum[i]-sum[i-1]<<" ";
}
cout<<endl;
}
return 0;
}
UVALive - 3523
算法:双连通分量,割点问题
注释:
#include
#include
#include
#include
#include
#define N 1010
#define M 1000010
using namespace std;
struct edge{
int u,v;
};
int n,m,bccno[N],pre[N],low[N],bcc_cnt,dfs_clock,color[N]; //注意变量类型
bool A[N][N],iscut[N],odd[N];
vector<int>G[N],bcc[N];
stack<edge>s;
void init()
{
memset(A,0,sizeof(A));
memset(bccno,0,sizeof(bccno));
memset(pre,0,sizeof(pre));
memset(low,0,sizeof(low));
memset(iscut,0,sizeof(iscut));
memset(color,0,sizeof(color));
memset(odd,0,sizeof(odd));
for(int i=1;i<=n;i++)
G[i].clear();
while(!s.empty())s.pop();
bcc_cnt=dfs_clock=0;
}
int dfs(int u,int fa)
{
int lowu=pre[u]=low[u]=++dfs_clock;
int child=0;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
edge e=(edge){u,v};
if(!pre[v])
{
s.push(e);
int lowv=dfs(v,u);
lowu=min(lowu,lowv);
child++;
if(lowv>=pre[u])
{
iscut[u]=1;
bcc_cnt++;
bcc[bcc_cnt].clear();
for(;;)
{
edge x=s.top();s.pop();
if(bccno[x.u]!=bcc_cnt)
{
bccno[x.u]=bcc_cnt;
bcc[bcc_cnt].push_back(x.u);
}
if(bccno[x.v]!=bcc_cnt)
{
bccno[x.v]=bcc_cnt;
bcc[bcc_cnt].push_back(x.v);
}
if(x.u==u&&x.v==v)break;
}
}
}
else if(pre[v]<pre[u]&&v!=fa)
{
s.push(e);
lowu=min(lowu,pre[v]);
}
}
if(fa==0&&child==1)iscut[u]=0;
low[u]=lowu;
return lowu;
}
void find_bcc(int n)
{
for(int i=1;i<=n;i++)
if(!pre[i])dfs(i,0);
}
bool partite(int u,int cnt)
{
//cout<
//for(int i=1;i<=n;i++)
//cout<
//cout<
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(bccno[v]!=cnt)continue;
if(color[u]==color[v])return false;
if(color[v]==0)
{
color[v]=3-color[u];
if(!partite(v,cnt))return false;
}
}
return true;
}
int main()
{
//freopen("1.txt","w",stdout);
int u,v;
bool flag=false;
while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
{
init();
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
A[u][v]=A[v][u]=1;
}
for(int i=1;i<=n;i++)
{
//G[i].clear();
for(int j=i+1;j<=n;j++)
if(!A[i][j])
{
G[i].push_back(j);
G[j].push_back(i);
}
}
find_bcc(n);
for(int i=1;i<=bcc_cnt;i++)
{
//cout<
//if(bcc[i].size()<=2)continue;
memset(color,0,sizeof(color));
for(int j=0;j<bcc[i].size();j++)
{
bccno[bcc[i][j]]=i;
//color[bcc[i][j]]=0;
// cout<
}
//cout<
color[bcc[i][0]]=1;
if(!partite(bcc[i][0],i))
{
//cout<
for(int j=0;j<bcc[i].size();j++)
odd[bcc[i][j]]=1;
}
}
int ans=n;
for(int i=1;i<=n;i++)
if(odd[i])ans--;
cout<<ans<<endl;
}
return 0;
}
UVALive - 5135
算法:双连通分量,割点割边
注释:
#include
#include
#include
#include
#include
#define N 100010
#define ll long long
using namespace std;
struct edge{
int u,v;
};
int dfs_clock,bcc_cnt,pre[N],low[N],bccno[N];
bool iscut[N];
vector<int>G[N],bcc[N];
stack<edge>s;
void init(int n)
{
memset(pre,0,sizeof(pre));
memset(low,0,sizeof(low));
memset(bccno,0,sizeof(bccno));
memset(iscut,0,sizeof(iscut));
while(!s.empty())s.pop();
for(int i=1;i<=N;i++)//初始化一定要完整
G[i].clear();
dfs_clock=bcc_cnt=0;
}
int dfs(int u,int fa)
{
int lowu=pre[u]=low[u]=++dfs_clock;
int child=0;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
edge e=(edge){u,v};
if(!pre[v])
{
s.push(e);
int lowv=dfs(v,u);
lowu=min(lowu,lowv);
child++;
if(lowv>=pre[u])
{
iscut[u]=1;
bcc_cnt++;
bcc[bcc_cnt].clear();
for(;;)
{
edge x=s.top();s.pop();
if(bccno[x.u]!=bcc_cnt)
{
bccno[x.u]=bcc_cnt;
bcc[bcc_cnt].push_back(x.u);
}
if(bccno[x.v]!=bcc_cnt)
{
bccno[x.v]=bcc_cnt;
bcc[bcc_cnt].push_back(x.v);
}
if(x.u==u&&x.v==v)break;
}
//cout<
}
}
else if(pre[v]<pre[u]&&v!=fa)
{
s.push(e);
lowu=min(lowu,pre[v]);
}
}
if(fa==0&&child==1)iscut[u]=0;
low[u]=lowu;
return lowu;
}
void find_bcc(int n)
{
for(int i=1;i<=n;i++)
if(!pre[i])dfs(i,0);
}
int main()
{
int m,n,u,v,t=0;
while(scanf("%d",&m)!=EOF&&m)
{
t++;
ll ans=0,tot=1;
n=0;//n需要初始化
init(m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
n=max(n,max(u,v));
}
//cout<
find_bcc(n);
for(int i=1;i<=bcc_cnt;i++)
{
ll num=0;
//cout<
for(int j=0;j<bcc[i].size();j++)
{
u=bcc[i][j];
// cout<
if(iscut[u])num++;
}
//cout<
if(num==1)
{
ans++;
tot=tot*(ll)(bcc[i].size()-1);
}
}
if(bcc_cnt==1)
{
ans=2;
tot=(ll)bcc[1].size()*(bcc[1].size()-1)/2;
}
cout<<"Case "<<t<<": "<<ans<<" "<<tot<<endl;
}
return 0;
}
UVALive - 4287
算法:强连通分量,拓扑排序,缩点
注释:
性质一:DAG中所有入度不为0的点,一定可以从某个入度为0的点出发可达。
性质二:从DAG上任何一个点出发不断往前走必然终止于一个出度为0的点。
/*DAG:有向无环图*/
#include
#include
#include
#include
#include
#define N 20010
using namespace std;
vector<int>G[N],scc[N],G2[N];
int pre[N],low[N],dfs_clock,sccno[N],scc_cnt,exp[N],imp[N];
stack<int>s;
void init(int n)
{
dfs_clock=scc_cnt=0;
memset(pre,0,sizeof(pre));
memset(low,0,sizeof(low));
memset(sccno,0,sizeof(sccno));
memset(exp,0,sizeof(exp));
memset(imp,0,sizeof(imp));
while(!s.empty())s.pop();
for(int i=1;i<=n;i++)
{
G[i].clear();
scc[i].clear();
G2[i].clear();
}
}
int dfs(int u)
{
//cout<
low[u]=pre[u]=++dfs_clock;
s.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
//cout<
if(!pre[v])
{
dfs(v);
low[u]=min(low[v],low[u]);
}
else if(!sccno[v])
{
low[u]=min(low[v],low[u]);
}
}
if(low[u]==pre[u])
{
scc_cnt++;
while(1)
{
int v=s.top();s.pop();
sccno[v]=scc_cnt;
scc[scc_cnt].push_back(v);
if(v==u)break;
}
}
}
void find_scc(int n)
{
for(int i=1;i<=n;i++)
if(!pre[i])dfs(i);
}
int main()
{
int t,n,m,u,v;
scanf("%d",&t);
while(t--)
{
int a=0,b=0;
scanf("%d%d",&n,&m);
init(n);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
}
find_scc(n);
for(u=1;u<=n;u++)
{
for(int j=0;j<G[u].size();j++)
{
v=G[u][j];
if(sccno[v]!=sccno[u])
{
exp[sccno[u]]++;
imp[sccno[v]]++;
}
}
}
for(int i=1;i<=scc_cnt;i++)
{
if(!exp[i])a++;
if(!imp[i])b++;
}
if(scc_cnt==1)
cout<<0<<endl;
else cout<<max(a,b)<<endl;
}
return 0;
}
UVA - 11324
算法:缩点,强连通分量,拓扑排序,线性DP
注释:
#include
#include
#include
#include
#include
#include
#define N 1010
using namespace std;
int pre[N],low[N],dfs_clock,sccno[N],scc_cnt,imp[N],num[N],maxn;
bool vis[N];
vector<int>G[N],T[N],scc[N];
stack<int>s;
queue<int>q;
void init(int n)
{
memset(pre,0,sizeof(pre));
memset(low,0,sizeof(low));
memset(sccno,0,sizeof(sccno));
memset(imp,0,sizeof(imp));
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
maxn=dfs_clock=scc_cnt=0;
for(int i=0;i<=n;i++)
{
G[i].clear();
T[i].clear();
scc[i].clear();
}
while(!s.empty())s.pop();
while(!q.empty())q.pop();
}
void dfs(int u)
{
//cout<
pre[u]=low[u]=++dfs_clock;
s.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!pre[v])
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if(!sccno[v])
{
low[u]=min(low[u],low[v]);
}
}
if(pre[u]==low[u])
{
scc_cnt++;
while(1)
{
int v=s.top();
s.pop();
sccno[v]=scc_cnt;
scc[scc_cnt].push_back(v);
if(v==u)break;
}
}
}
void find_scc(int n)
{
for(int i=1;i<=n;i++)
if(!pre[i])
dfs(i);
}
void tupo()
{
for(int i=1;i<=scc_cnt;i++)
{
if(!imp[i])
q.push(i);
num[i]=scc[i].size();
maxn=max(maxn,num[i]);
}
int u,v;
while(!q.empty())
{
u=q.front();
q.pop();
for(int i=0;i<T[u].size();i++)
{
v=T[u][i];
num[v]=max(num[v],num[u]+(int)scc[v].size());
maxn=max(maxn,num[v]);
imp[v]--;
if(!imp[v])q.push(v);
}
}
}
int main()
{
//freopen("1.txt","r",stdin);
//freopen("2.txt","w",stdout);
int t,n,m,u,v;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
//if(t==9)cout<
init(n);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
//if(t==9)cout<
G[u].push_back(v);
}
find_scc(n);
for(u=1;u<=n;u++)
{
for(int j=0;j<G[u].size();j++)
{
v=G[u][j];
if(sccno[u]!=sccno[v])
{
imp[sccno[v]]++;
T[sccno[u]].push_back(sccno[v]);
}
}
}
tupo();
cout<<maxn<<endl;
}
return 0;
}
UVALive - 3211
算法:dfs,2-SET问题,二分
#include
#include
#include
#include
#include
#include
#define N 2010
using namespace std;
struct TwoSET{
bool mark[N<<1];
vector<int>G[N<<1];
stack<int>s;
int n;
void init(int n)
{
this->n=n;
memset(mark,0,sizeof(mark));
for(int i=0;i<n*2;i++)G[i].clear();//注意初始化时应该初始化的点
}
void add_clause(int x,int xval,int y,int yval)
{
x=x*2+xval;
y=y*2+yval;
G[x^1].push_back(y);
G[y^1].push_back(x);
}
bool dfs(int u)
{
if(mark[u^1])return false;
if(mark[u])return true;
mark[u]=true;
s.push(u);
for(int i=0;i<G[u].size();i++)
if(!dfs(G[u][i]))return false;
return true;
}
bool solve()
{
for(int i=0;i<n*2;i+=2)
{
if(!mark[i]&&!mark[i+1])
{
while(!s.empty())s.pop();
if(!dfs(i))
{
while(!s.empty())
{
mark[s.top()]=false;
s.pop();
}
if(!dfs(i+1))return false;
}
}
}
return true;
}
};
int n,T[N][2];
TwoSET solver;
bool test(int diff)
{
solver.init(n);
for(int i=0;i<n;i++)for(int a=0;a<2;a++)
for(int j=i+1;j<n;j++)for(int b=0;b<2;b++)
if(abs(T[i][a]-T[j][b])<diff)solver.add_clause(i,a^1,j,b^1);
return solver.solve();
}
int main()
{
int l,r;
while(scanf("%d",&n)==1&&n)
{
l=r=0;
for(int i=0;i<n;i++)
for(int j=0;j<2;j++)
{
scanf("%d",&T[i][j]);
r=max(r,T[i][j]);
}
while(l<r)
{
int mid=(l+r+1)>>1;
if(test(mid))l=mid;
else r=mid-1;
}
cout<<r<<endl;
}
return 0;
}
UVALive - 3713
算法:2-SET
注释:
#include
#include
#include
#include
#include
#define N 100010
#define ll long long
using namespace std;
struct TwoSET{
int n;
bool mark[N<<1];
vector<int>G[N<<1];
stack<int>s;
void init(int n)
{
this->n=n;
memset(mark,0,sizeof(mark));
for(int i=0;i<n*2;i++)G[i].clear();
}
void add_clause(int x,int xtype,int y,int ytype)
{
x=x*2;
y=y*2;
if(xtype==ytype)
{
//cout<<"相同"<
G[x].push_back(y^1);
G[y].push_back(x^1);
G[x^1].push_back(y);
G[y^1].push_back(x);
}
else
{
//cout<<"不相同"<
G[y^1].push_back(x);
G[x^1].push_back(y);
}
}
bool dfs(int u)
{
if(mark[u^1])return false;
if(mark[u])return true;
mark[u]=true;
s.push(u);
for(int i=0;i<G[u].size();i++)
if(!dfs(G[u][i]))return false;
return true;
}
bool solve()
{
for(int i=0;i<2*n;i+=2)
{
if(!mark[i]&&!mark[i^1])
{
while(!s.empty())s.pop();
if(!dfs(i))
{
while(!s.empty())
{
mark[s.top()]=false;
s.pop();
}
if(!dfs(i+1))return false;
}
}
}
return true;
}
};
TwoSET solver;
ll age[N],type[N],n,m;
int main()
{
int x,y;
while(scanf("%d%d",&n,&m)==2&&(n+m))
{
ll tot=0;
for(int i=0;i<n;i++)
{
type[i]=0;
scanf("%d",&age[i]);
tot+=age[i];
}
solver.init(n);
for(int i=0;i<n;i++)
{
if(age[i]*n>=tot)type[i]=1;
else type[i]=2;
}
for(int i=0;i<m;i++)
{
cin>>x>>y;
solver.add_clause(x-1,type[x-1],y-1,type[y-1]);
}
if(solver.solve())
{
for(int i=0;i<n;i++)
{
if(solver.mark[i*2])
printf((type[i]==1?"A\n":"B\n"));
else if(solver.mark[i*2+1])
printf("C\n");
}
}
else printf("No solution.\n");
}
return 0;
}
UVA - 11396
算法:二分图判定
注释:
#include
#include
#include
#include
#define N 310
using namespace std;
vector<int>G[N];
int n,color[N];
void init(int n)
{
for(int i=0;i<=n;i++)
{
G[i].clear();
color[i]=0;
}
}
bool bipartite(int u)
{
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(color[v]==color[u])return false;
if(!color[v])
{
color[v]=3-color[u];
if(!bipartite(v))return false;
}
}
return true;
}
int main()
{
//freopen("1.txt","w",stdout);
int u,v;
while(scanf("%d",&n)&&n)
{
init(n);
while(scanf("%d%d",&u,&v)&&(u+v))
{
G[u].push_back(v);
G[v].push_back(u);
}
color[1]=1;
if(bipartite(1))printf("YES\n");
else printf("NO\n");
}
return 0;
}