病毒传播
思路:应该是比较简单的一道题,因为点数是千数量级的,floyd肯定不行了,看到边数也是1000,这就暗示了要从边下手,直接bfs找每个S集合内的点到各点的最短路这就是O(n*m),S不连通则无满足点,否则寻找S集合内满足以下条件的点:
对于S中的点x,到达S中除x外任意点距离 <= t && 到达G-S集合点距离 > t 的点x
思路不难,但是也卡了不少时间,只因为最后用auto k : mp 寻找S内满足条件的点之前,所有点x都被mp[x]这样访问过了,因此实际上auto k:mp 等价于for( int i = 1 ; i <= n ; i++ );再加上没有用本地IDE,调试也废了不少时间,记录下以前没注意的
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 1e3 + 6 ;
int n , m ;
int k , t ;
vector<int>G[AX] ;
map<int,int>mp ;
vector<int>res ;
int dis[AX][AX] ;
struct Node{
int u , d ;
Node(){}
Node( int u , int d ):u(u),d(d){}
} ;
int vis[AX] ;
void bfs( int x ){
queue<Node>q ;
q.push( Node( x , 0 ) ) ;
vis[x] = 1 ;
while( !q.empty() ){
Node k = q.front() ; q.pop() ;
int u = k.u ;
int d = k.d ;
for( int i = 0 ; i < (int)G[u].size() ; i++ ){
int v = G[u][i] ;
if( !vis[v] ) { dis[x][v] = d + 1 ; q.push(Node(v,d+1)) ; vis[v] = 1 ;}
}
}
}
void solve(){
for( auto i : mp ){
memset( vis , 0 , sizeof(vis) ) ;
bfs( i.first ) ;
}
for( int i = 1 ; i <= n; i++ ){
if( !mp[i] ) continue ;
int j ;
for( j = 1 ; j <= n ; j++ ){
if( i == j ) continue ;
if( mp[j] && ( dis[i][j] == -1 || dis[i][j] > t ) ) break ;
if( !mp[j] && dis[i][j] != -1 && dis[i][j] <= t ) break ;
}
if( j > n || ( i == n && j == n ) ) res.push_back(i) ;
}
}
int main(){
int u , v ;
cin >> n >> m ;
memset( dis , -1 , sizeof(dis) ) ;
for( int i = 0 ; i < m ; i++ ){
cin >> u >> v ;
if( u == v ) continue ;
G[u].push_back(v) ;
G[v].push_back(u) ;
}
cin >> k >> t ;
for( int i = 0 ; i < k ; i++ ){
cin >> u ;
mp[u] = 1 ;
}
solve();
int len = res.size() ;
if( !len ) cout << "-1" << endl;
else{
for( int i = 0 ; i < len ; i ++ ){
cout << res[i] ;
if( i != len - 1 ) cout << ' ' ;
}
}
return 0 ;
}
公交车
思路:对于每个公交线路创建一个虚拟点,连接这条线路的所有点。对构造的图求1-n最短路,距离/2即为答案(因为多了到虚拟点的距离
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std ;
typedef pair<int,int>P ;
const int AX = 1e5 + 666 ;
struct Node{
int v , w , nxt ;
Node(){}
Node( int v , int w , int nxt ):v(v),w(w),nxt(nxt){}
}G[AX<<1] ;
int tot ;
int head[AX] ;
int vis[AX] ;
int dis[AX] ;
int n , m ;
void add( int u , int v , int w ){
G[tot] = Node( v , w , head[u] ) ; head[u] = tot ++ ;
G[tot] = Node( u , w , head[v] ) ; head[v] = tot ++ ;
}
void djistra(){
memset( dis , 0x3f , sizeof(dis) ) ;
priority_queue<P , vector<P> , greater<P> > q ;
q.push(P(0,1)) ;
dis[1] = 0 ;
while( !q.empty() ){
P tmp = q.top() ;
q.pop() ;
int u = tmp.second ;
int w = tmp.first ;
vis[u] = 1 ;
for( int i = head[u] ; ~i ; i = G[i].nxt ){
int v = G[i].v ;
if( !vis[v] && dis[v] > dis[u] + G[i].w ){
dis[v] = dis[u] + G[i].w ;
q.push( P( dis[v] , v ) ) ;
}
}
}
}
int main(){
int x , y ;
memset( head , -1 , sizeof(head) ) ;
memset( vis , 0 , sizeof(vis) ) ;
scanf("%d%d",&n,&m);
for( int i = 1 ; i <= m ; i++ ){
scanf("%d",&x);
while( x-- ){
scanf("%d",&y);
add( y , n + i , 1 );
}
}
djistra();
printf("%d\n",( dis[n] == INF ? -1 : dis[n] / 2 ) );
return 0 ;
}
共享单车
思路:分层图最短路,在最短路基础上加一维是否骑车即可。
#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int AX = 1e5 + 666 ;
int n , m ;
int tot ;
int mark[AX] ;
int vis[5][AX] ;
struct Node {
int v , w , nxt ;
Node() {}
Node( int v , int w , int nxt ):v(v),w(w),nxt(nxt) {}
} G[AX<<1];
struct RES {
int u , sta ;
LL w ;
RES() {}
RES( int u , int sta , LL w ):u(u),sta(sta),w(w) {}
bool operator < ( const RES &a )const {
return w > a.w ;
}
};
int head[AX] ;
LL dis[5][AX] ;
void add( int u , int v , int w ) {
G[tot] = Node( v , w , head[u] ) ;
head[u] = tot++ ;
G[tot] = Node( u , w , head[v] ) ;
head[v] = tot++ ;
}
void dijstra() {
priority_queue<RES> q;
if( mark[1] ) {
q.push(RES(1,1,0)) ;
dis[1][1] = 0 ;
}
q.push(RES(1,0,0)) ;
dis[0][1] = 0 ;
while( !q.empty() ) {
RES tmp = q.top() ;
q.pop() ;
int u = tmp.u ;
int sta = tmp.sta ;
vis[sta][u] = 1 ;
for( int i = head[u] ; ~i ; i = G[i].nxt ) {
int v = G[i].v ;
LL w = G[i].w ;
if( sta == 1 && !vis[1][v] && dis[1][v] > dis[1][u] + (LL)(w / 2) ) {
dis[1][v] = dis[1][u] + (LL)(w / 2) ;
q.push(RES(v,1,dis[1][v]));
}
if( sta == 0 && !vis[0][v] && dis[0][v] > dis[0][u] + w ) {
dis[0][v] = dis[0][u] + w ;
q.push(RES(v,0,dis[0][v]));
}
if( sta == 0 && mark[v] && !vis[1][v] && dis[1][v] > dis[0][u] + w ){
dis[1][v] = dis[0][u] + w ;
q.push(RES(v,1,dis[1][v]));
}
}
}
}
int main() {
scanf("%d%d",&n,&m);
int x , y , w , k ;
memset( head , -1 , sizeof(head) ) ;
memset( vis , 0 , sizeof(vis) );
memset( mark , 0 , sizeof(mark) );
memset( dis , 0x3f , sizeof(dis) );
tot = 0 ;
for( int i = 0 ; i < m ; i++ ) {
scanf("%d%d%d",&x,&y,&w);
if( x == y ) continue ;
add( x , y , w ) ;
}
scanf("%d",&k);
for( int i = 0 ; i < k ; i++ ) {
scanf("%d",&x);
mark[x] = 1 ;
}
dijstra();
if( dis[0][n] == INF && dis[1][n] == INF ) printf("-1\n");
else printf("%lld\n",min(dis[0][n],dis[1][n]));
return 0 ;
}
重要节点
思路:图正反各存一遍,枚举每个点为起点,求能到达的点与能到自己的点的数量,比较大小。
#include <bits/stdc++.h>
using namespace std;
const int AX = 1e3 + 666 ;
int vis[AX] ;
vector<int>G[5][AX] ;
int ans[5] ;
void dfs( int x , int id ) {
vis[x] = 1 ;
ans[id] ++ ;
for( int i = 0 ; i < G[id][x].size() ; i++ ) {
int y = G[id][x][i] ;
if( !vis[y] ) dfs( y , id ) ;
}
}
int main() {
int n , m ;
scanf("%d%d",&n,&m);
int x , y ;
while( m-- ) {
scanf("%d%d",&x,&y);
if( x == y ) continue ;
G[0][x].push_back(y) ;
G[1][y].push_back(x) ;
}
int res = 0 ;
for( int i = 1 ; i <= n ; i++ ) {
ans[0] = 0 ;
ans[1] = 0 ;
memset( vis , 0 , sizeof(vis) ) ;
dfs( i , 0 ) ;
memset( vis , 0 , sizeof(vis) ) ;
dfs( i , 1 ) ;
if( ans[1] > ans[0] ) res ++ ;
}
printf("%d\n",res);
return 0 ;
}
K的倍数
思路:求前缀和并对每个位置对k取余,余数相等的两个位置中间的和必能整除k。记录最长的
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int AX = 1e5 + 66 ;
int a[AX] ;
LL sum[AX] ;
int main(){
int n ;
scanf("%d",&n);
sum[0] = 0 ;
for( int i = 1 ; i <= n ; i++ ){
scanf("%d",&a[i]);
sum[i] = sum[i-1] + a[i] ;
}
int k ;
scanf("%d",&k);
map<int,int>mp;
int res = 0 ;
for( int i = n ; i >= 1 ; i-- ){
sum[i] %= k ;
if( !sum[i] ) res = max( res , i ) ;
if( mp[sum[i]] ) res = max( res , mp[sum[i]] - i );
mp[sum[i]] = max( mp[sum[i]] , i ) ;
}
printf("%d\n",res) ;
return 0 ;
}
思路:floyd算法求得任意两点的最短路,然后dfs暴力求和。
#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int AX = 1e2 + 66 ;
int n , K ;
LL dis[AX][AX] ;
vector<int>b;
LL res ;
void dfs( int i , LL sum ) {
if( sum >= res ) return ;
if( i > K ) return ;
if( i == K ) {
res = min( res , sum ) ;
return ;
}
for( int j = i + 1 ; j < K ; j++ ) {
swap( b[i+1] , b[j] ) ;
dfs( i + 2 , sum + dis[b[i]][b[i+1]] ) ;
swap( b[i+1] , b[j] ) ;
}
}
int main() {
scanf("%d",&n);
int x ;
res = INF ;
for( int i = 1 ; i <= n ; i++ ) {
for( int j = 1 ; j <= n ; j++ ) {
scanf("%d",&x);
dis[i][j] = ( ( x == -1 ) ? INF : x ) ;
if( i == j ) dis[i][j] = 0 ;
}
}
for( int k = 1 ; k <= n ; k++ ) {
for( int i = 1 ; i <= n ; i++ ) {
for( int j = 1 ; j <= n ; j++ ) {
dis[i][j] = min( dis[i][j] , dis[i][k] + dis[k][j] );
}
}
}
scanf("%d",&K) ;
K *= 2 ;
for( int i = 0 ; i < K ; i++ ) {
scanf("%d",&x);
b.push_back(x) ;
}
dfs( 0 , 0 );
printf("%lld\n",res);
return 0 ;
}