POJ 2443Set Operation(好題! 每32位壓縮處理)
Set Operation
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 2286 | Accepted: 876 |
Description
You are given N sets, the i-th set (represent by S(i)) have C(i) element (Here "set" isn't entirely the same as the "set" defined in mathematics, and a set may contain two same element). Every element in a set is represented by a positive number from 1 to 10000.
Now there are some queries need to answer. A query is to determine whether two given elements i and j belong to at least one set at the same time. In another word, you should determine if there exist a number k (1 <= k <= N) such that element i belongs to
S(k) and element j also belong to S(k).
Input
First line of input contains an integer N (1 <= N <= 1000), which represents the amount of sets. Then follow N lines. Each starts with a number C(i) (1 <= C(i) <= 10000), and then C(i) numbers, which are separated with a space, follow to give the element in
the set (these C(i) numbers needn't be different from each other). The N + 2 line contains a number Q (1 <= Q <= 200000), representing the number of queries. Then follow Q lines. Each contains a pair of number i and j (1 <= i, j <= 10000, and i may equal to
j), which describe the elements need to be answer.
Output
For each query, in a single line, if there exist such a number k, print "Yes"; otherwise print "No".
Sample Input
3 3 1 2 3 3 1 2 5 1 10 4 1 3 1 5 3 5 1 10
Sample Output
Yes Yes No No
Hint
The input may be large, and the I/O functions (cin/cout) of C++ language may be a little too slow for this problem.
題目大意:題目意思很簡單,給你n個集合,每個集合有若干個元素。問你是否存在一個集合使得a,b都在裡面。
解題思路:現在考慮時間複雜度,n為10^3,元素的個數為10^4,查詢語句q為10^5.自己開始寫的是直接10^5*10^3,還需要考慮測試資料的組數,這樣查詢肯定會超時。當時用vector,把一個元素出現的行儲存起來,查詢的時候看元素a在哪些行出現過,然後列舉這些行是否出現過b。那樣訪問的次數就會少很多,不過還是很險會超時,2800ms.
題目地址:Set Operation
沒有壓縮處理的AC程式碼:
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<set>
#include<vector>
using namespace std;
int n;
short visi[1002][10002];
struct mm
{
int aa;
int bb;
int fla;
};
mm node[200002];
vector<int> mq[10002];
vector<int>::iterator it;
int main()
{
int i,j,t,x,q,flag;
int a,b;
int tt;
while(~scanf("%d",&n))
{
for(i=0;i<n;i++)
for(j=1;j<=10000;j++)
visi[i][j]=0;
for(i=1;i<=10000;i++)
mq[i].clear();
for(i=0;i<n;i++)
{
scanf("%d",&t);
for(j=0;j<t;j++)
{
scanf("%d",&x);
visi[i][x]=1;
mq[x].push_back(i);
}
}
scanf("%d",&q);
int len=0;
for(i=0;i<q;i++)
{
flag=0;
scanf("%d%d",&a,&b);
tt=0;
for(j=0;j<len;j++) //如果已經訪問過,就不往下找了,直接輸出
{
if((a==node[j].aa&&b==node[j].bb)||(b==node[j].aa&&a==node[j].bb))
{
tt=1;
flag=node[j].fla;
break;
}
}
if(tt)
{
if(flag) printf("Yes\n");
else printf("No\n");
}
else //沒訪問過,暴力列舉a存在的所有的行,看b是否存在
{
for(it=mq[a].begin();it!=mq[a].end();it++)
{
int tmp=*it;
if(visi[tmp][b])
{
flag=1;
break;
}
}
if(!flag)
{
node[len].aa=a,node[len].bb=b,node[len].fla=0;
printf("No\n");
}
else
{
node[len].aa=a,node[len].bb=b,node[len].fla=1;
printf("Yes\n");
}
}
}
}
return 0;
}
//2797MS
下面這種方法就很精妙了,關鍵需要這種思維方式。我們通過一個元素在某一行存在與否可以得到一個01矩陣,就是上面寫的visi矩陣。如果按照開始寫的方式,那麼就是列舉1000行看看是否有visi[i][a]與visi[i][b]相與為1的情況,如果有,說明a,b在第i行兩個一起出現過。不過這種方法的時間複雜度就是上面計算的10^8而且還沒計算測試的資料量。肯定會超時。我們可以把每32行儲存到一個int裡面,按位壓縮。這樣時間複雜度就降為了10^6。這種方法真的很奇特!
AC程式碼:
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<set>
#include<vector>
using namespace std;
int n;
short visi[1002][10002];
int p[10002][32]; //把每個元素存在每32行壓縮到到一個int內
int main()
{
int i,j,k,t,x,q,flag;
int a,b;
int len; //分成32位的長度
while(~scanf("%d",&n))
{
for(i=0;i<n;i++)
for(j=1;j<=10000;j++)
visi[i][j]=0;
for(i=1;i<=n;i++)
{
scanf("%d",&t);
for(j=0;j<t;j++)
{
scanf("%d",&x);
visi[i][x]=1;
}
}
len=n/32;
if(n%32!=0)
len++;
for(i=0;i<len-1;i++) //壓縮處理
{
for(j=1;j<=10000;j++)
{
p[j][i]=0;
int tmp=1;
for(k=1+i*32;k<=32+i*32;k++)
{
p[j][i]+=visi[k][j]*tmp;
tmp<<=1;
}
}
}
for(j=1;j<=10000;j++)
{
p[j][i]=0;
int tmp=1;
for(k=1+i*32;k<=n;k++)
{
p[j][i]+=visi[k][j]*tmp;
tmp<<=1;
}
}
scanf("%d",&q);
for(i=0;i<q;i++)
{
flag=0;
scanf("%d%d",&a,&b);
for(j=0;j<len;j++)
{
if(p[a][j]&p[b][j]) //兩個相與得到1說明有一行a,b都存在
{
flag=1;
break;
}
}
if(flag) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
//891MS
相關文章
- 批處理壓縮
- Gulp壓縮報錯處理
- zip壓縮檔案處理方案(Zip4j壓縮和解壓)
- java中 檔案壓縮處理Java
- .Net Core HttpClient處理響應壓縮HTTPclient
- Delphi資料壓縮處理(1) (轉)
- Delphi資料壓縮處理(2) (轉)
- web前端實現圖片壓縮處理Web前端
- SpringBoot-檔案壓縮處理Spring Boot
- POJ3279 Fliptile【狀態壓縮+DFS】
- ffmpeg-圖片壓縮旋轉等處理
- png格式如何壓縮,圖片壓縮工具哪個好
- 批處理 壓縮zip 並過濾部分檔案
- 有手就會的 Java 處理壓縮檔案Java
- ORA-27300 OS system dependent operation:if_not_found 問題處理
- -bash: ulimit: max user processes: cannot modify limit: Operation not permitted問題的處理MIT
- Nginx網路壓縮 CSS壓縮 圖片壓縮 JSON壓縮NginxCSSJSON
- JAVA壓縮和解壓縮Java
- zip壓縮和解壓縮
- Linux每程式執行緒數問題處理Linux執行緒
- linux壓縮解壓縮Linux
- 字串的壓縮和解壓縮字串
- 檔案壓縮和解壓縮
- 移動開發時批處理壓縮圖片提高開發效率移動開發
- 小技巧:不用任何媒體處理軟體進行視訊壓縮
- 直播原始碼網站,js處理圖片變形、方向、壓縮等原始碼網站JS
- C# 關於壓縮、加密、解壓問題C#加密
- JS壓縮方法及批量壓縮JS
- aix 下壓縮與解壓縮AI
- linux壓縮和解壓縮命令Linux
- tar 分卷壓縮&解壓縮命令
- AIX 上壓縮與解壓縮AI
- Android 圖片處理之固定視框中的等比例壓縮Android
- 檢測壓縮包並處理的Linux指令碼(解壓、批量修改檔名、匯入)分析Linux指令碼
- android 關於Bitmap壓縮處理解析Android
- linux下壓縮解壓縮命令Linux
- linux壓縮和解壓縮命令整理Linux
- 簡單的zip壓縮和解壓縮